装饰者模式适合这里吗

Is decorator pattern suitable here

所以我有几个 classes,ABC,... N。还有一些可能的属性,setP()setQ()setR()、... setZ()。现在,每个 class 可以有不同的属性组合:

A          B          C          N
- setX     - setR     - setP     - setY
- setY     - setZ     - setQ     - setZ
- setZ                - setR
                      - setS
                      - setZ

所有 setters return 对象本身的实例,以便可以进行链接。

我正在尝试找到一种优雅的方法来解决这个问题。我不想重新定义每个 class 中的数十个属性(代码重复),我也不想使用继承,因为会有丑陋、毫无意义的中间 classes (BaseABCD -> setZ) 和 cuz基础 class setter 将 return 类型 BaseABCD 的实例,这将不允许所有属性的完整链接。

以下是我正在尝试研究的一些可能的事情:

  1. 以某种方式将每个 属性 定义为优雅时尚的装饰器,并组成 A 类似于 Base.decorators().addX().addY().addZ().finalize().

  2. Base 中定义所有可能的属性,并在派生的 class 中隐藏不需要的属性。我认为这是不可能的。

这些事情有可能吗?或者有更好的办法来解决这样的问题吗?


更多详情

classes 基本上是应用程序用来与外部系统通信的不同消息类型。不同的消息包含不同类型的不同字段。例如:

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>。每个 属性 对应于 class 的哈希图中的一个键。序列化时,我只是遍历 class 哈希图中的所有 key/value 条目并生成要发送的字符串消息表示形式。

但是,我想对调用者代码强制执行类型。所以我不想公开像 A.set('RESOURCEIDENTIFIER', '123456') 这样的方法。相反,我想公开 A.setResourceIdentifier(123456)C.setOperation(OperationType.DELETE).

等方法

在内部,这些 setter 函数只是将相关键放入哈希图中并为其分配一个字符串值。

public A setOperation(OperationType operation) {
    this.hashmap.put('OPERATION', operation.name());
    return this;
}

大约有 40 种独特的字段类型,所有消息都使用这些字段的独特子集。像 AB 包含 setTimestamp()BC 包含 setResourceIdentifier()。只有 C 包含 setOperationType()。等等。

我不想一遍又一遍地在每个class中重新定义这几十个属性。这就是为什么我想探索以下两个选项:

选项 1 定义具有所有可能属性的 Base class,并在派生的 A class 中,仅将必需的属性覆盖为 public。这是可行的。但我想看看是否有可能实现选项 #2 中描述的内容。

选项 2 以某种方式定义装饰器和工厂 class 这样

public ? getA() {
    return Base.startDecorating()
        .addTimestamp()
        .addResourceIdentifier()
        .finalize();
}

? objA = Factory.getA()
    .setTimestamp(DateTime.now())
    .setResourceIdentifier(123456);

这可能吗?在写出这个问题时,我意识到选项 1 应该是可行的方法。它简单且不易出错。但出于好奇,我想知道装饰器模式是否可以在这里使用。毕竟,我这里有一套完整的独立模块(属性)和将它们组装在一起的不同方式(classes)。

根据属性的名称,我猜您是在尝试定义不同的坐标表示法?为什么不使用具有所有属性的一个基数 class?

这些实际上并没有那么多属性,您不能将它们组合成随机排列。那么,为什么要把每件事都变得比必要的更复杂呢?

我认为 Decorator 不适合这里:装饰器的意义在于保持透明。如果您这样定义您的属性,则必须检查(属性 的类型或是否存在)每次访问。

如果属性的 setter 中有一些在多个主要 class 中共享的逻辑,装饰器模式可以适合并且是一种很好的设计方法。如果不是,例如你确定他们所做的只是 this.x=x 或者每个 class 设置一个 属性 某种类型的不同然后没有。

您可以为每个属性定义一个 class,并让您的主要 classes 具有属性类型 classes 的变量。这样,当在主 class 上设置 属性 时,它会将工作委托给适当的 属性 class 的 setter,这样您就可以定义setter 一次使用,随处使用。同样,如果您在 setter 中有更多逻辑然后 this.x=x;,这可能是最好的主意。

哦,在将设置的作业委托给 属性 class 之后,您仍然可以 return this 进行链接。

此外,如果您懒惰并且不太关心实时性能,您可以使用反射来简化主要 classes 的编码。

装饰器是为您可以不断添加的东西而设计的。就像一棵圣诞树。但是一旦圣诞树装饰好了,那么你就可以使用turnOn()这样的常用方法。它不是为向现有 API 添加新方法而制作的。我认为您可以为此使用常规的旧继承。我也会使用像 List 这样的例子。你的Baseclass可以提供大家共享的常用方法,然后互相子class添加新的方法。

为了帮助保持清洁,您可以添加工厂或生成器来简化操作。

这里有一些例子。假设基数class被称为Base,sub-classes是一个名为classes、AB等的字母

  1. 工厂示例1.

    Base x = factory.getInstance(A.class);

  2. 工厂示例2.

    Map props = ...; Base x = factory.getInstance(A.class, props);

  3. 生成器示例 1.

    Base x = new ABuilder().setX(x).setY(y).setZ(z).create();

这涉及为每个单独的子 class 创建构建器 class。子 class 构建器 classes 可能继承也可能不继承抽象 BaseBuilder class,后者定义了带有签名 public Base create();.

的方法