0

我正在设计一个我必须做的项目。为此,我曾考虑使用装饰器设计模式。但是,我必须根据项目的现有实施调整我的设计。然后,我不能完全保留装饰器设计模式。

该项目有一个抽象基类(称为A)和一组子类(称为A1、A2、A3、A4等)。我无法修改这些类的代码。

然后,我必须为这些类添加额外的功能。为此,我创建了一个用于 A 类(装饰器)的抽象类(称为 B)。我还创建了用于 A1、A2、A3、A4、... 类的具体装饰器

注意:如您所见,我不使用任何接口,因为 A 类不使用任何接口,我无法修改此代码。

但是我在这个设计中看到了一些问题:

1) 类 B1,B2,B3,B4,... 必须添加类 A1,A2,A3,A4,... 的所有方法以调用 A1,A2,A3,A4... 类的方法... 例如,在 B1 类中:

    class B1 {
      public A1 objectA1;

      B1() {
          objectA1 = new A1();
      }

      public void add(int value) {
          objectA1.add(value);
          // extra funcionality
      } 
    }    

这可能是个问题,因为如果其他开发人员修改 A、A1、A2、A3、A4、...类的代码,他们还需要修改 B、B1、B2、B3、B4、...的代码为了防止这种情况。

2)此外,类 A、A1、A2、A3、A4 具有只能从自己的类或子类访问的受保护方法。由于我需要访问这些方法,我不能使用装饰器设计模式。

第二种选择

我可以用 B1、B2、B3、B4 扩展 A1、A2、A3、A4 类。例如:

    class B1 extends A1 {

      B1() {
          objectA1 = new A1();
      }

      public void add(int value) {
          super.add(value);
          // extra funcionality
      } 
    }    

这样,我解决了第二个问题,避免覆盖 A1 的所有方法,只覆盖必要的方法。即便如此,每次创建 A 的子类时,都必须创建相应的 B 类。我想防止这种情况发生,因为只需要 B 类(B1,B2,...)覆盖类的方法一个(A1,A2,...)。

第三种选择

然后,我认为我可以考虑将 B 类(B1,B2,...)作为 A 类(A1,A2,...)的包装器。这样,将创建一个 B 的实例,如下所示:

    new BMaker.get(A1, params_of_constructor_A1)
    new BMaker.get(A2, params_of_constructor_A2)
    new BMaker.get(A3, params_of_constructor_A3)
    new BMaker.get(A4, params_of_constructor_A4) or 
    ...
    new BMaker.get(AN, params_of_constructor_AN)

其中 BMaker.get 是一个静态方法。

    public static <T extends A> A get (T objectA, params ) {
        // return anonymous class (*1)
    }

我的问题是,是否有可能实现一个继承 A1、A2、... ,A2,A3,...

真的,我不知道是否有可能做到这一点,或者还有其他更好的方法。

任何帮助,将不胜感激!

4

1 回答 1

2

回答第一个问题:

  1. 要么将接口 I 放在 A 上,以便您的装饰器/代表可以实现相同的接口,或者

  2. 创建一个接口 I(相当于 A 的 api)和一个包装类 AW,它包装 A 并通过将所有调用直接传递给它来实现 I。

将您的客户端代码转换为使用 I 而不是 A,然后您可以愉快地继续使用新接口构建装饰器/或委托,并在 AW 中“包装”了旧的垃圾。

出现的一个值得注意的问题是,某些使用 A(IdentityHashMaps,持久性)的代码样式可能需要对“底层”A 的引用。如果出现这种情况,您可以在 interface 中放置一个方法getUnderlyingA()。尽量避免使用太多,因为它显然绕过了所有装饰。


第二个问题:装饰子类型。

这里的问题是子类型是否需要作为不同的装饰器类型公开 - 或者是否可以公开一个统一的装饰器,(可能,如果需要)在内部知道它可以包装的 A 子类型的类型系统。

如果子类型众所周知且稳定,您可以在接口中实现“句柄样式”api。例如,对于文件系统实体,您将提供单一类型的句柄,但提供isFile()isDirectory()isDevice()isDrive()isRaw()方法来查询该类型。可以使用一种listFiles()方法来使用目录子类型。

我的问题是为什么你需要外部访问(从装饰器)到受保护的方法?如果你这样做,这些方法应该是公开的,并且原始设计被破坏/扩展不足。

也许您可以在同一个包中创建一个静态帮助程序类(如果不更改 A 类本身),这将使您能够从装饰器中正确访问这个遗留垃圾。


这里有一个特定的点,正确地完成你的工作有时会涉及使用并可能升级遗留代码。如果没有有效且可维护的设计替代方案,那不应该是一个总的症结所在。将类型系统加倍(创建两个并行的层次结构)绝对不是您应该做的。

如果没有很好的方法来做到这一点,您应该处理其他事情(不同的功能/要求),而不是让代码库变得更糟。

于 2013-11-02T23:41:23.560 回答