装饰器模式失去虚拟方法查找。有什么好的替代方案或解决方法吗?

时间:2012-08-26 07:38:23

标签: java oop decorator virtual-functions

背景

我遇到以下情况:

我的Analyzer类型大致如下

interface Analyzer {
    int computeValue();
    String performAnalysis();
}

通过类似

的方式实现
class AnalyzerImpl implements Analyzer {

    @Override
    public int computeValue() {
        return 5;
    }

    @Override
    public String performAnalysis() {
        return "Result: " + computeValue();
    }
}

(在我的实际代码中,performAnalysis使用几种不同复杂度的computeValue方法执行许多计算。)

现在我需要在运行时有选择地调整Analyzer对象的行为(或者使用调整行为创建一个包装器)。

我尝试了什么:

我添加了调整方法:

public Analyzer tweakAnalyzer(Analyzer untweakedAnalyzer) { ... }

并尝试使用decorator pattern

解决它
class AnalyzerDecorator implements Analyzer {
    Analyzer delegate;
    public AnalyzerDecorator(Analyzer delegate) {
        this.delegate = delegate;
    }

    @Override
    public int computeValue() {
        return delegate.computeValue();
    }

    @Override
    public String performAnalysis() {
        return delegate.performAnalysis();
    }
}

然后我按如下方式实施tweakAnalyzer

public Analyzer tweakAnalyzer(Analyzer untweakedAnalyzer) {
    return new AnalyzerDecorator(untweakedAnalyzer) {
        @Override
        public int computeValue() {
            return 1337;              // tweaked value!
        }
    };
}

然而,在做的时候

tweakAnalyzer(new AnalyzerImpl()).performAnalysis();

我根据需要获得了未被识别的值 Result: 5,而不是Result: 1337

(这是因为调整后的分析器与未经过分析的分析器不是同一个对象,它只是一个包装器,因此computeValue中对AnalyzerImpl的调用不能按预期工作。)

Full ideone.com example.

TL; DR:

我想在运行时调整对象的行为。我使用了装饰器模式,但“丢失”了所有虚拟方法。

问题:

解决这个问题的最佳方法是什么,即我应该如何以某种方式调整Analyzer的行为,以便我不会松开虚拟方法查找或者无关紧要如果我这样做?

2 个答案:

答案 0 :(得分:5)

问题是你的装饰师没有被performAnalysis调用,因为它不知道你装饰了这个类。

您应该将performAnalysiscomputeValue分为两类(Analyzer performAnalysisCalculator computeValue

这样,您可以单独装饰它们,并将装饰好的计算器传递到Analyzer a'la performAnalysis(Calculator calculator)

示例at IDEOne。是的,它基本上是行动中的Strategy Pattern

答案 1 :(得分:1)

您是否可以访问分析器对象的代码?如果是这样,您可以使用策略模式将其设计为可调整。

替代方案(具有多次调度种类的模板模式):

abstract class Analyzer {

   public final int ComputeValue () {
      return doComputeValue (this);
   }

   public final string PerformAnalysis () {
      return doPerformAnalysis (this);
   }

   protected abstract int doComputeValue (Analyzer myself);
   protected abstract string doPerformAnalysis (Analyzer myself);
}

class AnalyzerImpl extends Analyzer {

   protected int doComputeValue (Analyzer myself) {
      ...
   }

   protected string doPerformAnalysis (Analyzer myself) {
      return "Result: " + myself.ComputeValue();
   }
}

class AnalyzerDecorator extends Analyzer {
    Analyzer delegate;
    ...
    protected string doPerformAnalysis (Analyzer myself) {
        return delegate.doPerformAnalysis (myself);
    }
    protected int doComputeValue (Analyzer myself) {
        return delegate.doComputeValue (myself);
    }
}