[英]An alternative for the Decorator pattern in Java?
假设您具有以下与统计信息相关的类的层次结构,其结构类似于Template方法模式 :
interface S {
// Method definitions up-to and including the S3 class
}
class S0 implements S {
// Code that counts samples
}
class S1 extends S0 {
// Code that calls the superclass methods and also computes the mean
}
class S2 extends S1 {
// Code that calls the superclass methods and also computes the variance
}
class S3 extends S2 {
// Code that calls the superclass methods and also computes the skewness
}
现在假设我们要扩展这些类中的每一个,以例如检查度量的收敛性。 出于我的目的,我不需要在运行时进行此扩展。 我可以想到以下替代方案:
分别从S0
, S1
, S2
和S3
创建子类S0C
, S1C
, S2C
和S3C
,每个子类均具有检查收敛性的代码副本:
使用装饰器模式 :
S
接口中添加例如收敛性检查方法,这完全破坏了任何模块化感。 取消此要求的唯一方法是在我的代码中禁止嵌套装饰器。 如果Java支持多重继承,那么我可能可以通过从统计信息和基本的收敛性检查(或其他)类继承来处理此问题。 Java,Java不支持多重继承(不,接口不计算在内!)。
有没有更好的方法来处理Java中的此问题? 也许是不同的设计模式? 更技术性的解决方案? 某种特殊的仪式舞蹈?
PS:如果我误解了什么,请随时(轻轻地)指出...
编辑:
看来我需要澄清一下我的目标:
我不需要运行时对象组成。 我想要的是用新方法扩展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 ...; } }
注意hasConverged()
方法的重复。
收敛检查装饰器将是这样的:
class CC<T extends S> implements S { T o = ...; int addSample(double x) { o.addSample(x); ...; } double getMean() { return o.getMean(); } boolean hasConverged() { return ...; } }
问题:如果除了融合检查之外,我还想结合其他分隔符行为,则需要一个单独的装饰器(例如NB
,并且为了访问例如hasConverged()
方法,新装饰器需要:
CC
相同的接口 CC
相同的接口来包装对象类型... CC
情况下将NB
与S*
对象一起使用,这迫使我对S*
方法使用该接口 我选择装饰器模式只是因为缺少更好的选择。 到目前为止,这只是我发现的最干净的解决方案。
扩展S*
类时,我仍然需要完整的原始文件。 将收敛功能放在通用的超类中,将意味着相关的行为(及其性能影响)现在将存在于所有子类中,这绝对不是我想要的。
根据您最近的编辑。
正如您可能已经意识到的那样,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);
}
}
运作方式
public interface IOp {
// Interface is optional. Just for flexibility.
public void Compute(List<Integer> data);
}
public class Op<T> implements IOp{
// Generics is also optional. I use this to standardise data type of Result, so that it can be polymorphically accessed.
// You can also put in some checks to make sure Result is initialised before it is accessed.
public T Result;
public void Compute(List<Integer> data);
}
class ComputeMeanOperation extends Op<double>{
public void Compute(List<Integer> data){
/* sum and divide to get mean */
this.Result = /* ... */
}
}
class CheckConvergenceOperation extends Op<boolean>{
public void Compute(List<Integer> data){
/* check convergence */
this.Result = /* ... */
}
}
用法
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);
}
优点:
缺点/局限性:
希望这符合您的要求:)
我糊涂了。 尚不清楚为什么需要第一个继承树。 像下面的代码这样的东西可以做到这一点:
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.