简体   繁体   English

限制不可变对象Java中的可变对象

[英]Restrict mutable object inside immutable object Java

I am learning about immutable Objects. 我正在学习不可变的对象。 I am trying this code 我正在尝试这段代码

  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;
    }
}

I want to restrict the calling class from changing the value of name variable of NormalObject 我想限制调用类更改NormalObject的name变量的值

But the following code changes the value 但是以下代码更改了值

 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

How to restrict it? 如何限制它?

For an object to be immutable, all of its properties must be immutable. 对于不可变的对象,其所有属性必须是不可变的。 Its state must not be changeable. 它的状态一定不可改变。

To do that, you have to put an immutable facade on NormalObject , you can't directly return a NormalObject . 要做到这一点,你必须在NormalObject上放置一个不可变的Facade,你不能直接返回一个NormalObject The method that returns it will also need a different return type, you can't return NormalObject but actually return something that doesn't behave like a NormalObject . 返回它的方法也需要一个不同的返回类型,你不能返回NormalObject但实际上返回的行为不像NormalObject

Eg: 例如:

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();
    }
}

Alternately, if it's acceptable to copy the object and it has a copy constructor (or you can add one), you could do that, but copy-and-return is expensive. 或者,如果复制对象并且它有一个复制构造函数(或者你可以添加一个)是可以接受的,那么你可以这样做,但复制和返回是很昂贵的。

You can do this by returning a copy of your normalObject in getter: 您可以通过在getter中返回normalObject的副本来完成此操作:

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

Or you can make a wrapper for your NormalObject that ignores name setter, but it brakes logic. 或者您可以为NormalObject创建一个忽略名称设置器的包装器,但它会制动逻辑。

Please change Your NormalObject code to 请将您的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;
    }
}

NormalObject Class NormalObject类

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;
    }*/

}

In an immutable object, if a User tries to change the state of the Object. 在不可变对象中,如果用户尝试更改Object的状态。 either you won't allow or return a new Instance of the Immutable class. 要么你不允许或返回一个新的Immutable类实例。

So, since Date is a mutable class. 所以,因为Date是一个可变类。 You can create an immutable wrapper around date, and you can expose only those methods, that are subject to be used in your Immutable-Date's perspective, but you return a new instance of your Immutable class, with the changed attribute of your new Date. 您可以在日期周围创建一个不可变的包装器,并且您只能公开那些可以在Immutable-Date的透视图中使用的方法,但是您返回一个新的Immutable类实例,其中包含新Date的已更改属性。

I don't think final would be required for Immutable variable, because it is already private and Immutable. 我不认为Immutable变量需要final,因为它已经是private和Immutable。

Example : 示例:

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();
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM