【问题标题】:Restrict mutable object inside immutable object Java在不可变对象Java中限制可变对象
【发布时间】:2014-11-28 13:00:23
【问题描述】:

我正在学习不可变对象。我正在尝试这段代码

  public final class ImmutableObject {

    private final String name;

    private final NormalObject obj =  new NormalObject();

    public String getName() {
        return name;
    }


    public ImmutableObject(String name) {
        this.name = name;
        obj.setName(name);
    }


    public NormalObject getObj() {

        NormalObject tempObj = obj;
        return tempObj;
    }
}

public class NormalObject {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

我想限制调用类改变 NormalObject 的 name 变量的值

但是下面的代码改变了值

 ImmutableObject obj = new ImmutableObject("Siddle");

 System.out.println(obj.getObj().getName()); //prints Siddle
 obj.getObj().setName("Kelly");

 System.out.println(obj.getObj().getName()); //prints Kelly

如何限制?

【问题讨论】:

    标签: java immutability


    【解决方案1】:

    对于一个不可变的对象,它的所有属性必须是不可变的。它的状态不能改变。

    为此,您必须在NormalObject 上放置一个不可变的外观,您不能直接返回NormalObject。返回它的方法也需要不同的返回类型,您不能返回 NormalObject,但实际上返回的行为不像 NormalObject

    例如:

    public final class ImmutableObject {
    
        private final String name;
    
        private final NormalObject obj =  new NormalObject();
    
        private final ImmutableNormalObject objFacade = new ImmutableNormalObject(obj);
    
        public String getName() {
            return name;
        }
    
        public ImmutableObject(String name) {
            this.name = name;
            obj.setName(name);
        }
    
        public ImmutableNormalObject getObj() {
    
            return objFacade;
        }
    }
    
    public class NormalObject {
    
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    public class ImmutableNormalObject {
    
        private NormalObject obj;
    
        public ImmutableNormalObject(Normalobject o) {
            this.obj = o;
        }
    
        public String getName() {
            return obj.getName();
        }
    }
    

    或者,如果复制对象是可以接受的并且它有一个复制构造函数(或者你可以添加一个),你可以这样做,但是复制和返回是昂贵的。

    【讨论】:

    【解决方案2】:

    您可以通过在 getter 中返回 normalObject 的副本来做到这一点:

    public NormalObject getObj() {
        return new NormalObject(obj.getName());
        // or you can make a copy constructor:
        // return new NormalObject(obj);
    }
    

    或者您可以为您的 NormalObject 创建一个忽略名称设置器的包装器,但它会破坏逻辑。

    【讨论】:

      【解决方案3】:

      请将您的 NormalObject 代码更改为

      public final class ImmutableObject {
      
          private final String name;
          // initialise it to null
          private final NormalObject obj = null;
      
          public String getName() {
              return name;
          }
      
      
          public ImmutableObject(String name) {
              this.name = name;
              // use the Constructor for setting name only once during initialization of ImmutableObject via its constructor
              obj =  new NormalObject(name);
      
              //obj.setName(name);
          }
      
      
          public NormalObject getObj() {
      
              NormalObject tempObj = obj;
              return tempObj;
          }
      }
      

      普通对象类

      public class NormalObject {
      
          private String name;
          public NormalObject(name){
           this.name = name;
          }
          public String getName() {
              return name;
          }
          //Remove any setter on NormalObject
          /*public void setName(String name) {
              this.name = name;
          }*/
      
      }
      

      【讨论】:

      • 我喜欢 NormalObject 保持原样。我只想限制 ImmutableObject 的变量。
      【解决方案4】:

      在不可变对象中,如果用户尝试更改对象的状态。要么您不允许,要么返回 Immutable 类的新实例。

      所以,因为 Date 是一个可变类。 您可以围绕日期创建一个不可变的包装器,并且您可以只公开那些在您的 Immutable-Date 视角中使用的方法,但是您返回一个 Immutable 类的新实例,以及新 Date 的更改属性。

      我认为不可变变量不需要 final,因为它已经是私有且不可变的。

      例子:

      public class Main{
      
        private ImmutableDate immutableDate;
      
        public Main() {
          this.immutableDate = new ImmutableDate(new Date());
        }
      
        public Main(Date date){
          this.immutableDate = new ImmutableDate(date);
        }
      
        public ImmutableDate getDate() {
          return immutableDate;
        }
      
        public class ImmutableDate{
          // private constructor, so this can only be instantiated within the outer class
          // therefore, final keyword not required for Date, as no access given to the variable
          private Date date;
          private ImmutableDate(Date date) {
            this.date = date;
          }
      
          // Example methods from Date, that are required for our Immutable implementation
      
          public Main setTime(long time){
            Date date1 = new Date();
            date1.setTime(time);
            return new Main(date1);
          }
      
          @Override
          public String toString() {
            return date.toString();
          }
        }
      }
      

      【讨论】:

        猜你喜欢
        • 2021-05-04
        • 1970-01-01
        • 1970-01-01
        • 2012-07-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-01
        相关资源
        最近更新 更多