所以我有几个课程,A
,B
,C
,... N
。还有一些可能的属性,setP()
,setQ()
,setR()
,... setZ()
。现在,每个类可以有不同的属性组合:
A B C N
- setX - setR - setP - setY
- setY - setZ - setQ - setZ
- setZ - setR
- setS
- setZ
所有setter都返回一个对象本身的实例,以便链接成为可能。
我试图找到一种优雅的方法来解决这个问题。我不想重新定义每个类中的数十个属性(代码重复),我不想使用继承,因为会有丑陋的,无意义的中间类(BaseABCD -> setZ
)并且因为基类setter将返回一个实例键入BaseABCD
,它不允许完全链接所有属性。
以下是我试图研究的一些可能的事情:
以某种方式以优雅的方式将每个属性定义为装饰器,并撰写A
之类的Base.decorators().addX().addY().addZ().finalize()
。
在Base
中定义所有可能的属性,并隐藏派生类中的非必需属性。我不认为这是可能的。
这些事情有可能吗?或者是否有更好的想法来解决像这样的问题?
更多详情
这些类基本上是应用程序用来与外部系统通信的不同消息类型。不同的消息包含不同类型的不同字段。例如:
ECHO message:
- Timestamp (DateTime)
- SourceAddress (String)
CHECK RESOURCE message:
- Timestamp (DateTime)
- Resource Identifier (Integer)
MANIPULATE RESOURCE
- Resource Identifier (Integer)
- Operation Type (Enum)
传输时消息被序列化为字符串,并且不保留类型信息。所以我选择了HashMap<String, String>
。每个属性对应于该类的hashmap中的键。在序列化时,我只是迭代该类的hashmap中的所有键/值条目,并生成一个要发送的字符串消息表示。
但是,我想对调用者代码强制执行类型。所以我不想公开像A.set('RESOURCEIDENTIFIER', '123456')
这样的方法。相反,我想公开A.setResourceIdentifier(123456)
和C.setOperation(OperationType.DELETE)
等方法。
在内部,这些setter函数只是在hashmap中放入一个相关的键并为其赋值。
public A setOperation(OperationType operation) {
this.hashmap.put('OPERATION', operation.name());
return this;
}
大约有40种独特的字段类型,所有消息都使用这些字段的唯一子集。例如A
和B
包含setTimestamp()
。 B
和C
包含setResourceIdentifier()
。只有C
包含setOperationType()
。等等。
我不想一遍又一遍地重新定义每个班级中的这几十个属性。这就是我想探索以下两个选项的原因:
选项1
定义具有所有可能属性的Base
类,并在派生的A
类中,仅覆盖要公开的必需属性。这是可行的。但我想看看是否有可能实现选项#2中描述的内容。
选项2 以某种方式定义装饰器和工厂类
public ? getA() {
return Base.startDecorating()
.addTimestamp()
.addResourceIdentifier()
.finalize();
}
? objA = Factory.getA()
.setTimestamp(DateTime.now())
.setResourceIdentifier(123456);
这可能吗?在写出这个问题时,我意识到选项1应该是要走的路。它很简单,不易出错。但出于好奇,我想知道装饰模式是否可以在这里使用。毕竟,我在这里有一套完整的独立模块(属性)和不同的组合方式(类)。
答案 0 :(得分:2)
装饰器是为了你可以继续添加的东西。像一棵圣诞树。但是一旦装饰了圣诞树,你就会使用像turnOn()
这样的常用方法。它不是为现有API添加新方法。我认为你可以使用常规的旧继承。我也会使用像List这样的例子。您的Base类可以提供所有将共享的常用方法,然后每个其他子类将添加新方法。
为了帮助保持清洁,您可以添加工厂或构建器以简化操作。
以下是一些例子。假设基类被称为Base
,子类是一个名为classes的字母,A
,B
等。
工厂示例1。
Base x = factory.getInstance(A.class);
工厂示例2.
Map props = ...;
Base x = factory.getInstance(A.class, props);
构建器示例1。
Base x = new ABuilder().setX(x).setY(y).setZ(z).create();
这涉及为每个子类创建一个构建器类。子类构建器类可能会也可能不会从定义带有签名BaseBuilder
的方法的抽象public Base create();
类继承。
答案 1 :(得分:1)
如果属性的setter中有一些逻辑,这些逻辑在多个主类之间共享,那么装饰器模式可以适合并且是一种很好的设计方法。如果没有,例如你确定他们所做的一切都是this.x=x
,或者每个类都设置了某种类型的属性,然后是不。
您可以为每个属性定义一个类,并让您的主类具有属性类类型的变量。这样,当在主类上设置属性时,它会将作业委托给相应属性类的setter。这样,您可以定义属性的setter一次并在任何地方使用它们。同样,如果您在设置器中有更多逻辑然后this.x=x;
,这可能是最好的主意。
哦,在将设置作业委托给属性类之后,您仍然可以返回this
进行链接。
另外,如果你很懒惰并且不关心实时性能,你可以使用反射来简化主类的编码。
答案 2 :(得分:0)
根据属性的名称我猜你试图定义不同的坐标表示?为什么不使用一个具有所有属性的基类?
实际上并没有那么多属性,你可以将它们组合成随机排列。那么为什么要让每件事都变得更加复杂呢?
我认为装饰师不适合这里:装饰者的感觉是保持透明。如果您定义这样的属性,则必须检查(在属性的类型或存在上)每次访问。