在基类中具有对象实例化"挂钩"是否可以?

时间:2020-03-06 14:52:02  来源:igfitidea点击:

我出于各种原因创建了自己的Tree实现,并提出了两个类,一个"基本"类是一个充满逻辑的通用树节点,另一个是扩展了一个更专门的类的类。

在我的基类中,某些方法涉及实例化新的树节点(例如,添加子节点)。这些实例位于逻辑内部(例如在嵌套循环中),这使得逻辑很难与实例分离。

因此,如果我没有在特定的类中覆盖这些实例,则将创建错误的节点类型。但是,我不想覆盖这些方法,因为它们还包含不应重复的共享逻辑!

问题可以归结为:

public class Foo {
    public String value() { return "foo"; }

    public Foo doStuff() {
        // Logic logic logic..
        return new Foo();
    }
}

class Bar extends Foo {
    public String value() { return "bar"; } 
}

new Bar().doStuff().value(); // returns 'foo', we want 'bar'

首先出现在我脑海中的是一个"创建钩子",扩展类可以覆盖它:

public Foo createFooHook(/* required parameters */) {
  return new Foo();
}

现在。虽然这是一个很好的初步想法,但该代码会产生一些恶臭。有一些非常...错误的地方。

就像裸着做饭一样-感到危险和不必要。

那么,我们将如何处理这种情况?

解决方案

我认为没有更好的方法。请注意不要从构造函数中调用这些钩子。

因此,在获得设计模式的副本并将其打开后,我很确定这是我第一次发现自己想要的东西。

这被称为"工厂方法",并且基本上很适合。这仍然有点丑陋,因为我的超类(上例中的" Foo")不是抽象的,这意味着子类不会被强制实现该钩子。

不过,可以通过一些重构来解决这一问题,最后我得到一些效果:

abstract class AbstractFoo {
    public String value() { return "Foo"; }

    public AbstractFoo doStuff() {
        // Logic logic logic
        return hook();
    }

    protected abstract AbstractFoo hook();
}

class Foo extends AbstractFoo {
    protected AbstractFoo hook() { return new Foo(); }
}

class Bar extends AbstractFoo {
    public String value() { return "Bar"; }

    protected AbstractFoo hook() { return new Bar(); }
}

new Bar().doStuff().value(); // Returns 'Bar'!

除了Factory模式之外,我还将研究Composite模式,它很适合在基于树的情况下与Factory一起使用。

复合设计模式