把自己编成一个角落

时间:2010-01-14 18:32:12

标签: java design-patterns oop

我们有一组来自一组通用接口的类

IFoo-> BasicFoo, ReverseFoo, ForwardFoo
IBar -> UpBar, DownBar, SidewaysBar
IYelp -> Yip, Yap, Yup

其中Foo的构造函数看起来像Foo(IBar, IYelp)这些项目在整个项目中使用。

存在另一个类,其具有签名为public double CalcSomething(IFoo, IAnotherClass)的方法,该方法在某一点应用于每个Foo。我们已经从上面请求了一个特定的对象组合,比如说BasicFoo(UpBar,Yip),使用的算法与CalcSomething中的算法不同。

我的第一直觉是让我们改变IFoo接口,这样我们就可以将逻辑移到Foo类级别,将构造函数更改为Foo(IBar, IYelp, IStrategy),然后让Foo对象封装这个逻辑。不幸的是,我们也被告知架构的设计规定IFoo,它的实现和IAnotherClass之间没有依赖关系。他们坚持这一点。

好的,当然,我以为我可能会使用访客模式但是......怎么样?制作合成的全部意义在于,没有其他类可以看到实现细节。反思内部物体,完全打破封装?哦,没有。

所以我来这里是因为我不知所措。有没有人有任何建议我们如何处理其中一种成分的特殊情况而不改变成分或打破封装?必须有一个简单的解决方案,我过度看。

编辑:

删除了违规的开头。 将“特别处理”改为更具描述性的含义。

3 个答案:

答案 0 :(得分:3)

根据您提供的CalculationFactory类型选择适当算法的IFoo可以解决问题(以条件为代价):

interface ICalcSomethingStrategy {
    public double CalcSomething(IFoo, IAnotherClass);
}

CalcSomethingStrategyFactory {
    ICalcSomethingStrategy CreateCalcSomethingStrategy(IFoo foo) {
        // I'm not sure whether this is the idiomatic java way to check types D:
        if (foo.Bar instanceof UpBar && foo instanceof Yip) {
            return new UnusualCalcSomethingStrategy();
        } else {
            return new StandardCalcSomethingStrategy();
        }
    }
}

答案 1 :(得分:3)

本着KISS的精神,我会向IFoo添加一个方法isSpecial(),并使用它来决定在CalcSomething()中使用哪种算法。

这假设这是唯一的特例。

答案 2 :(得分:1)

calcSomething无法避免获得执行“特殊”行为所需的知识,但除此之外,您可以通过这种方式维护大部分封装。

创建一个标记接口IQualifyForSpecialTreatment,它扩展了IFoo。将BasicFoo扩展到SpecialBasicFoo,并使其实现IQualifyForSpecialTreatment。


    interface IQualifyForSpecialTreatment extends IFoo {
    }
    class SpecialBasicFoo extends BasicFoo implements IQualifyForSpecialTreatment {
        ...
    }

然后你可以添加另一种calcSomething:


    calcSomething (IQualifyForSpecialTreatment foo, IAnotherClass whatever) {
        ... perform "special" variant of calculation
    }
    calcSomething (IFoo foo, IAnotherClass whatever) {
        ... perform "normal" variant of calculation
    }