【问题标题】:Java best practice for outside access to inner private class fields外部访问内部私有类字段的 Java 最佳实践
【发布时间】:2018-01-04 15:54:44
【问题描述】:

我搜索了很多关于我的问题的答案并找到了几个选项,想知道你这是最佳做法。

用例: 所以我有一个单例类AccontManager,它有一个只与它相关的内部类,它是一个User 类。

public class AccontManager {

private static final AccountManger ourInstance = new AccountManger();
private User user;

public static AccountManger getInstance()
{
    return ourInstance;
}

private AccountManger(){}

public User getUser(){
    return this.user;
}

private class User{
    private String id;
    
    private User (String id){
        this.id = id;
    }
}
}

现在的情况是User字段必须访问外部包类,但用户类只对这个单例类是唯一的,因此内部类必须是私有的。

最好在内部类中创建公共 getter 方法来获取用户字段,但由于内部类是私有的,所以这是不可能的。

可能的做法:

  1. 实践:在User 字段的外部AccountManager 类中创建相应的getter 方法。

    缺点:用户字段与User 相关,因此外部类不应对其字段具有getter 方法。

    代码示例

     public class AccountManger {
    
         private static final AccountManger ourInstance = new AccountManger();
         private User user;
    
         public static AccountManger getInstance()
         {
             return ourInstance;
         }
    
         private AccountManger(){}
    
         public User getUser(){
             return this.user;
         }
    
         public String getUserId() // <-- get User id
         {
             return user.id;
         }
    
         private class User{
             private String id;
    
             private User (String id){
                 this.id = id;  
          }  
     }
     }
    
  2. 实践:将User修饰符更改为public,但保持构造函数私有,因此无法实例化。

    缺点:内部的User 类将作为AccountManager 单例类的成员可见,这是不应该的。

    代码示例

     public class AccountManager {
    
         private static final AccountManger ourInstance = new AccountManager();
         private User user;
    
         public static AccountManager getInstance()
         {
             return ourInstance;
         }
    
         private AccountManger(){}
    
         public User getUser(){
             return this.user;
         }
    
         public String getUserId() // <-- get User id
         {
             return user.id;
         }
    
         private class User{
             private String id;
    
             private User (String id){
                 this.id = id;
             }
         }
         }  
    
  3. 练习

  • 创建一个公共接口,例如IUser
  • 使内部类User 实现该接口
  • 添加到外部类,在这种情况下AccountManagerUser 实例的getter 方法

缺点:需要使用接口才能从User获取数据。

代码示例

    public class AccountManager {
    
    private static final AccountManager ourInstance = new AccountManager();
    private User user;

    public interface IUser{
        String getName();
    }

    private AccountManager(){}

    public static AccountManager getInstance(){
        return ourInstance;
    }

    public User getUser(){
        return this.user;
    }

    private class User implements IUser{
        private String id;

        private User(String id){
            this.id = id;
        }

        @Override
        public String getName() { // <-- get user id
            return id;
        }
    }
    }

所以你怎么看? 列出的任何一个选项? 还有什么办法?

感谢您的意见

【问题讨论】:

    标签: java inner-classes


    【解决方案1】:

    我想说User 类必须是private,并且AccountManager 应该实现getterssetters 到它的属性。

    您不必知道User 是什么,因为AccountManager 会告诉您可以知道的内容。另外,您可以服从Law of Demeter,这总是一件好事。

    IMO,内部类应该用作使外部类中的代码更干净的一种方式,它们不应该能够在其他地方使用。

    但我想将 User 中的构造函数设为私有总比没有好。

    【讨论】:

      【解决方案2】:

      我看到了三种替代方法:

      • 使 User 类独立且公开(如有必要,并为其提供 AccountManager 字段)。然后 User 成为您公共 API 的一部分 - 可能不是您想要的。

      • 在 AccountManager 类中,为公共相关的用户属性创建 getter 和 setter。这使 User 实体成为 Account Manager 的不可见组件。 (类比:如果你谈论你的汽车的马力,你就是在隐瞒它不是汽车本身的属性,而是它的引擎的属性,这很好)。

      • 如果您希望用户的概念成为 API 的一部分,但仍希望保持内部 User 类私有,请使用公共相关方法创建接口 IUser 并让 User 实现 IUser。然后你可以在你的AccountManager中暴露一个public IUser getUser()方法,外界只能看到接口中声明的功能。

      【讨论】:

        【解决方案3】:

        看到AccountManager(您在代码示例中拼错了“Manager”)是一个单例类,它不会真正产生有效的区别,但您自己说“用户类只对这个单例是唯一的class”,所以如果你将 static 设为 User 类的目的可能会更好地体现出来。

        无论如何,在您的原始代码示例中,您包含了一个方法public User getUser()。类Userprivate,我真的看不出这样做有什么意义,因为在类AccountManager 之外,任何对User 对象的引用都是无用的,因为你将永远无法访问它的任何成员或声明一个User 变量,将由此获得的User 引用分配给该变量。我能想到的唯一可能的用例是AccountManager 声明一个接受User 参数的public(或任何高于User 的访问修饰符)方法。但即使是这样,我也会质疑这样的设计是否真的是你想要的。

        因此,您可能需要考虑是否真的需要方法public User getUser(),前提是User 保持private。这已经将我们引向您最初的问题。我认为您提出的第一个解决方案更好。对我来说,这似乎正是允许超类访问子类的“私有”成员的原因。引用自stackoverflow 上的this answer

        内部类(出于访问控制的目的)被认为是包含类的一部分。这意味着可以完全访问所有隐私。

        因此,如果您认为UserAccountManager 的一部分,那么您不必对从AccountManager 内部而是从User 外部访问其private 字段感到内疚,因为显然, Java 的设计者也会这样想。

        最后,如果您不打算在 User 存在期间更改字段 id,则可以将 id 改为 final

        【讨论】:

          猜你喜欢
          • 2013-11-18
          • 1970-01-01
          • 2013-09-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-07-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多