Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中装饰器模式的替代方案?_Java_Oop - Fatal编程技术网

Java中装饰器模式的替代方案?

Java中装饰器模式的替代方案?,java,oop,Java,Oop,假设您有以下与统计信息相关的类的层次结构,其结构类似于: 假设现在我们想要扩展这些类中的每一类,例如检查度量的收敛性。出于我的目的,我不需要在运行时进行此扩展。我可以想到以下几种选择: 分别从S0、S1C、S2C和S3C创建子类S0C、S1、S2和S3,每个子类都带有检查收敛性的代码副本: 优点: 概念上直截了当 结果对象仍然属于超类 子类源代码仅包含附加的收敛检查代码 缺点: 大量的代码重复-在将来会导致更改同步开销 主要缺点: 如果我需要另一组类,例如预处理样本,该怎么办?我们

假设您有以下与统计信息相关的类的层次结构,其结构类似于:

假设现在我们想要扩展这些类中的每一类,例如检查度量的收敛性。出于我的目的,我不需要在运行时进行此扩展。我可以想到以下几种选择:

  • 分别从
    S0
    S1C
    S2C
    S3C
    创建子类
    S0C
    S1
    S2
    S3
    ,每个子类都带有检查收敛性的代码副本:

    • 优点:
      • 概念上直截了当
      • 结果对象仍然属于超类
      • 子类源代码仅包含附加的收敛检查代码
    • 缺点:
      • 大量的代码重复-在将来会导致更改同步开销
    • 主要缺点:
      • 如果我需要另一组类,例如预处理样本,该怎么办?我们谈论的是同一代码的指数复制
  • 使用:

    • 优点:
      • 没有代码重复
    • 缺点:
      • 对象不再属于原始类(易于处理)
      • 由于使用了虚拟方法调用,而不是特殊的方法调用,Java中的性能受到了非常轻微的影响(它是存在的!我测量过了!)。这不是很重要,但仍然很明显
    • 主要缺点:
      • 关于大量必须与包装对象接口保持同步的委托方法。使用接口确实可以确保不会遗漏任何方法,但即使使用自动生成委托方法的IDE,也很难维护
      • 为了有一个正确实现的decorator模式,所有decorator和包装类都需要实现完全相同的接口。这本质上意味着我必须在
        S
        接口中添加收敛性检查方法,这完全破坏了模块化的感觉。 解除此要求的唯一方法是禁止代码中的嵌套装饰符
如果Java支持多重继承,我可能已经能够通过从统计数据和基本收敛检查(或其他)类继承来处理这个问题。唉,Java不支持多重继承(不,接口不算数!)

有没有更好的方法在Java中处理这个问题?也许是另一种设计模式?更具技术性的解决方案?某种特殊的仪式舞蹈

如果我误解了什么,请(轻轻地)指出

编辑:

看来我需要澄清一下我的目标:

  • 我不需要运行时对象组合。我想要的是用新方法扩展
    S*
    类的功能。如果我可以根据需要创建子类而不需要代码复制,我可能会这样做。如果我能在使用的地方做(不太可能),那就更好了

  • 我不想一遍又一遍地写同样的代码。注意:委托方法和构造函数是好的,我想实现算法的方法不是

  • 我想保持我的接口模块化。这是我对Decorator模式的主要问题-除非放置了非常具体的嵌套约束,否则最终会得到一个包含所有接口的超级接口

编辑2:

针对其中一些评论:

  • S*
    类是使用模板方法构造的:

    class S0 {
       int addSample(double x) {
          ...;
       }
    
      double getMean() {
          return Double.NaN;
      }
    }
    
    class S1 extends S0 {
    
    
       int addSample(double x) {
          super.addSample(x);
          ...;
       }
    
       double getMean() {
          return ...;
       }
    }
    
  • 我的
    S*C
    第一个解决方案中的扩展类如下所示:

    interface S {
        int addSample(double x);
        double getMean();
    }    
    
    class S0C extends S0 implements S {
       int addSample(double x) {
          super.addSample(x);
          ...;
       }
    
       boolean hasConverged() {
          return ...;
       }
    }
    
    class S1C extends S1 {
       int addSample(double x) {
          super.addSample(x);
          ...;
       }
    
       boolean hasConverged() {
          return ...;
       }
    }
    
    class CC<T extends S> implements S {
       T o = ...;
    
       int addSample(double x) {
          o.addSample(x);
          ...;
       }
    
       double getMean() {
          return o.getMean();
       }    
    
       boolean hasConverged() {
          return ...;
       }
    }
    
    请注意
    hasConvergend()
    方法的重复

  • 收敛检查装饰器如下所示:

    interface S {
        int addSample(double x);
        double getMean();
    }    
    
    class S0C extends S0 implements S {
       int addSample(double x) {
          super.addSample(x);
          ...;
       }
    
       boolean hasConverged() {
          return ...;
       }
    }
    
    class S1C extends S1 {
       int addSample(double x) {
          super.addSample(x);
          ...;
       }
    
       boolean hasConverged() {
          return ...;
       }
    }
    
    class CC<T extends S> implements S {
       T o = ...;
    
       int addSample(double x) {
          o.addSample(x);
          ...;
       }
    
       double getMean() {
          return o.getMean();
       }    
    
       boolean hasConverged() {
          return ...;
       }
    }
    
    类CC实现了{ To=。。。; int addSample(双x){ o、 添加样品(x); ...; } 双getMean(){ 返回o.getMean(); } 布尔收敛(){ 返回。。。; } } 问题:如果我想结合收敛检查之外的另一个分隔符行为,我需要一个单独的装饰器,例如
    NB
    ——为了访问例如
    hasConvergend()
    方法,新的装饰器需要:

    • 实现与
      CC
    • 对其包装对象类型使用与
      CC
      相同的接口
    • …这迫使我将该接口用于
      S*
      方法,如果我希望能够在不使用
      CC的情况下将
      NB
      S*
      对象一起使用
  • 我选择的装饰风格只是因为缺少更好的选择。这是迄今为止我找到的最干净的解决方案

  • 在扩展
    S*
    类时,我仍然需要原样。例如,将聚合功能放在一个通用的超类中意味着相关的行为(及其性能影响)现在将存在于所有子类中,这绝对不是我想要的


    • 我很困惑。不清楚为什么需要第一个继承树。类似下面的代码可以完成这项工作:

      public class Statistics 
      {
          void add(final double x) 
          {
              sum  += x;
              sum2 += x * x;
              sum3 += x * x * x;
              n++;
          }
          double mean() 
          {
              return n != 0 ? sum / n : 0;
          }
          double variance() 
          {
              return n != 0 ? ( sum2 - sum * sum / n) / (n - 1) : 0;
          }
      
          // add method for skewness
          double sum, sum2, sum3;
          int n;
      }
      

      基于您最近的编辑

      正如您可能已经意识到的,Decorator不适合这种情况。这是因为它解决的是单个功能的扩充,而不是整个类树的扩充

      实现这一目标的一种可能方式是采用战略。策略以算法为中心;它允许您解耦行为代码(如果有一点C#在这里和那里滑落,那就很抱歉了)


      样本类

      public class S {
         private List<Integer> Samples = new List<Integer>(); 
      
         public void addSample(int x){
            Samples.Add(new Integer(x));
         }
      
         public void Process(IOp[] operations){
            for (Op operation : operations){
                Process(operation);
            }
         }
         public void Process(ICollection<IOp> operations){
            for (Op operation : operations){
                Process(operation);
            }
         }
         public void Process(IOp operation){
            operation.Compute(this.Samples);
         }
      }
      
      公共类S{
      私有列表示例=新列表();
      公共void addSample(int x){
      添加(新的整数(x));
      }
      公共作废流程(IOp[]操作){
      
      public static void main(String args[]) {
          S s = new S();
          s.addSample(1);
          /* ... */
      
          ComputeMeanOperation op1 = new ComputeMeanOperation();
          CheckConvergenceOperation op2 = new CheckConvergenceOperation ();        
      
          // Anonymous Operation
          Op<Integer> op3 = new Op<Integer>(){
             public void Compute(List<Integer> samples){
                 this.Result = samples[0]; // Gets first value of samples
             }
          }
      
          s.Process(op1); // Or use overloaded methods
          s.Process(op2);
          s.Process(op3);
      
          System.out.println("Op1 result: " + op1.Result); 
          System.out.println("Op2 result: " + op2.Result);
          System.out.println("Op3 result: " + op3.Result);
      }