Java 有没有实现holder对象的可变和不可变版本的模式?

Java 有没有实现holder对象的可变和不可变版本的模式?,java,design-patterns,immutability,Java,Design Patterns,Immutability,在我的应用程序中,holder对象的类型很少,其主要目的是存储异构相关数据。其生命周期可分为两部分: 一旦数据可用,立即收集数据 在持有者的余生中提供对存储数据的只读访问 使持有者不可变很有诱惑力,但是数据不能一次性传递给构造函数。我看到的最简单的解决方法是创建两个holder类版本,一个是可变的,另一个是不可变的: public class MutableHolder { public int field1; public String field2; // ...

在我的应用程序中,holder对象的类型很少,其主要目的是存储异构相关数据。其生命周期可分为两部分:

  • 一旦数据可用,立即收集数据
  • 在持有者的余生中提供对存储数据的只读访问
  • 使持有者不可变很有诱惑力,但是数据不能一次性传递给构造函数。我看到的最简单的解决方法是创建两个holder类版本,一个是可变的,另一个是不可变的:

    public class MutableHolder {
        public int field1;
        public String field2;
        // ...
        public Object fieldN;
    }
    
    public class Holder {
        public final int field1;
        public final String field2;
        // ...
        public final Object fieldN;
    
        public Holder(MutableHolder mutableHolder) {
            this.field1 = mutableHolder.field1;
            this.field2 = mutableHolder.field2;
            // ...
            this.fieldN = mutableHolder.fieldN;
        }
    }
    
    但是,我觉得这种方法违反了DRY原则(如果我想更改任何内容,我不能忘记更新两个类的字段以及构造函数),并且容易出错。所以我的问题是:有没有我不知道的实现holder对象的可变和不可变版本的现有模式

    编辑
    我突然发现上面的代码是构建器模式的一个非常简单的版本(请参见或)。这使我认为在这种情况下,干法违规被认为是可以接受的。

    另一种可能的解决方案是。因为它的主要概念是当一个对象的状态改变时改变它的行为。还允许对象在其内部状态更改时更改其行为。对象将显示为更改其类

    在你的案例中,你可以考虑以下的实施:

    //maintains an instance of a ConcreteState subclass that defines the current state
    public class Holder {
        //your code
    }
    
    //encapsulating the behavior associated with a particular state of the Holder
    public abstract class State{
        //your code
    }
    
    //implements a behavior associated with a state of Holder
    public class MutableHolderState extends State {
        //your code
    }
    
    //implements a behavior associated with a state of Holder
    public class ImmutableHolderState extends State {
        //your code
    }
    

    我也在这个问题上绊倒了一段时间。这是我提出的一个设计模式,我在其他地方没有见过

    public class Bob
    {
        // member variables
        private int value;
    
        // simple constructor
        private Bob()
        {
            value(0);
        }
    
        // constructor with value
        private Bob(int value)
        {
            value(value);
        }
    
        // get value
        public final int value()
        {
            return this.value;
        }
    
        // set value
        private final void value(int value)
        {
            this.value = value;
        }
    
    
        // mutable class modifies base class
        public static class Mutable extends Bob
        {
            // simple constructor
            private Mutable()
            {
                super();
            }
    
            // constructor with value
            private Mutable(int value)
            {
                super(value);
            }
    
            // set value
            public final void value(int value)
            {
                super.value(value);
            }
        }
    
    
        // factory creator for immutable
        public static final Bob immutable(int value)
        {
            return new Bob(value);
        }
    
        // factory creator for mutable
        public static final Mutable mutable()
        {
            return new Mutable();
        }
    
        // another mutable factory creator
        public static final Mutable mutable(int value)
        {
            return new Mutable(value);
        }
    }
    
    • 类不是最终的,子类化应该是安全的
    • 所有构造函数都必须是私有的
    • 公共访问器应该是最终的
    • 基类中的私有变量应该是final
    • 可变类中的公共变量应该是final
    • 使用工厂方法构造不可变和可变对象
    这类似于子类mutable模式,但由于mutable类是一个内部类,它可以访问基类中的私有字段和方法,因此不需要保护任何可能被重写的内容。基类就像一个标准的可变类,不同的是构造函数和变异子是私有的。可变子类是一个薄层(每个方法都是超级的…),它公开了变异子


    创建不可变实例:Bob test1=Bob.immutable(99);创建可变实例:Bob.mutable test2=Bob.mutable()

    依我看,你问错了问题。你的问题是你的数据在你需要的时候不可用。您可能需要重新构造代码以允许创建对象?@bwa遗憾的是,我找不到实现这一点的方法。数据是通过使用流解析器TagSoup解析网页获得的。它不构建DOM,所以我不能在一个地方访问整个页面,而是在找到开始标记、结束标记或字符序列时调用回调。如果不能使对象不可变,就不能使其不可变。不需要两个版本。只需使其可变,并注意尽快填写所需的所有数据。使对象不可变将有助于使您的代码变得更好-如果这项工作太多或使代码在过程中变得更复杂,那么尝试就没有意义了。@B我会考虑这一点。谢谢您的建议,但我认为这种解决方案只会使事情变得过于复杂。在其基础上,它由与构建器模式中相同的两个类(实际持有者和临时构建器)组成,并添加了额外的胶水,在我的例子中,这没有任何价值。