2

到目前为止,我已经多次遇到这个设计问题,并且我总是通过以下方式解决它。但是,我只是想知道这是否是正确的方法,或者是否有更好的方法。语言是 Java,但我猜这个问题也会出现在其他强类型系统中。

问题是这样的:

abstract class P
{
   int p1; int p2;
}

class P1 extends P {
   int p3; int p4;
}

class P2 extends P {
   int p5; int p6;
}

abstract class PHandler {
    void handle(P p)
}

class P1Handler{
    void handle(P p) {
          P1 castedP = (P1) p;
          //.....handle logic with P1
    }
}

class P2Handler{
    void handle(P p) {
          P2 castedP = (P2) p;
          //.....handle logic with P2
    }
}

final class PHandlerFactory {
    PHandler getPhandler(P p) {
       //test on P , if/else on either InstanceOf or some attribute of P
       return concrete P
    }
}

// client code

P p = getPFromSomewhereAtRuntime();
PHandler pHandler = factory.get(p);
pHandler.handle(p);

现在,这段代码从未让我完全满意。

第一,我不喜欢具体的 PHandler 中的铸造。具体的 PHandlers 知道他们想要在编译时处理的类型。为什么要等到运行时?(它是一种 Java 语言限制,可以通过诸如双重调度之类的任何技术来避免?无法理解它)

2、工厂紫罗兰OPEN-CLOSED-PRINCIPLE。我通常通过反射/属性文件来实现它以避免OCP。编辑:随着我们继续添加更多 P 实例,我们需要不断更改工厂(除非使用反射)

我还在 Concrete P 实现中使用了注解。再一次,它会破坏 OCP,更糟糕的是,P 可以有不同类型的 Handlers 用于不同的目的。

我真的很想知道专家对此的看法。同样,这段代码主要在 Spring 容器中运行,因此任何其他 AOP 解决方案也会让我感兴趣。

4

2 回答 2

2

正如@bmorris591 所说,“泛型是整理它的方法”。但这可能只是因为您的示例足够简单,可以这样做。

这真的取决于上下文。您的代码编写方式让我想起了访问者模式。这是一种进行双重调度的方法。它有一些优点和缺点。最大的缺点是它会使您的代码复杂化。

在某些情况下,您使 P 成为 PHandler 的逻辑接口,如下所示:

interface P
{
   void handle();
}

class P1 implements P {
   int p3; int p4;
   void handle () {...}
}

class P2 implements P {
   int p5; int p6;
   void handle () {...}
}

同样,这有利也有弊。从 OO 的角度来看,将句柄实现放在 P 实现中可能没有意义。这一切都与上下文有关。

于 2013-03-26T01:10:48.563 回答
1

如果您知道 的具体实现P,即如果它们不是从某个地方提供的,那么您可以使用访问者模式:

abstract class P {

    int p1;
    int p2;

    abstract void visit(final PVisitor visitor);
}

class P1 extends P {

    int p3;
    int p4;

    @Override
    void visit(PVisitor visitor) {
        visitor.doStuff(this);
    }
}

class P2 extends P {

    int p5;
    int p6;

    @Override
    void visit(PVisitor visitor) {
        visitor.doStuff(this);
    }
}

interface PVisitor {

    void doStuff(P1 p);

    void doStuff(P2 p);
}

所以你有一个Collection<PVisitor>访问者逻辑,然后你P用你的 s 访问你的实例,PVisitor多态性将计算出什么是什么。

编辑

根据 OP 的评论,我有一个想法。

抽象工厂模式与访问者模式和一些泛型相结合呢?

我们的想法是,我们知道如果我们添加一种新的类型,Handler那么就需要改变一些东西——从逻辑上讲,它应该是HandlerFactory实现而不是Ps。如果我们有一个abstract HandlerFactory并且每个P实现负责返回一个处理它的实例怎么办。

然后,工厂有许多返回特定处理程序的方法,getDatabaseHandler例如等。这些Handler可以从泛型Handler类继承。

这个想法看起来像这样:

abstract class P {

    int p1;
    int p2;

    public abstract HandlerFactory<? extends P> getHandlerFactory();
}

class P1 extends P {

    int p3;
    int p4;

    @Override
    public HandlerFactory<P1> getHandlerFactory() {
        return new P1HandlerFactory(this);
    }
}

class P2 extends P {

    int p5;
    int p6;

    @Override
    public HandlerFactory<? extends P> getHandlerFactory() {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
}

abstract class HandlerFactory<T extends P> {

    private T t;

    public HandlerFactory(T t) {
        this.t = t;
    }

    public T getT() {
        return t;
    }

    public abstract DatabaseHandler<T> getDatabaseHandler();

    public abstract JMSHandler<T> getJMSHandler();
}

abstract class Handler<T extends P> {

    private final T t;

    public Handler(T t) {
        this.t = t;
    }

    public T getT() {
        return t;
    }
}

abstract class DatabaseHandler<T extends P> extends Handler<T> {

    public DatabaseHandler(T t) {
        super(t);
    }

    public abstract void persist(Connection con);
}

abstract class JMSHandler<T extends P> extends Handler<T> {

    public JMSHandler(T t) {
        super(t);
    }

    public abstract void send();
}

class P1HandlerFactory extends HandlerFactory<P1> {

    public P1HandlerFactory(P1 t) {
        super(t);
    }

    @Override
    public DatabaseHandler<P1> getDatabaseHandler() {
        return new P1DatabaseHandler(getT());
    }

    @Override
    public JMSHandler<P1> getJMSHandler() {
        return new P1JMSHandler(getT());
    }
}

class P1DatabaseHandler extends DatabaseHandler<P1> {

    public P1DatabaseHandler(P1 p1) {
        super(p1);
    }

    @Override
    public void persist(Connection con) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
}

class P1JMSHandler extends JMSHandler<P1> {

    public P1JMSHandler(P1 p1) {
        super(p1);
    }

    @Override
    public void send() {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
}

所以每个实现P都附带一个同伴HandlerFactory,添加一个新的实现P只需要HandlerFactory为它实现一个。例如,泛型的使用允许P1A并且P1B继承自,如果它们不需要任何更改,则P1仅使用 a 。P1Handler

如果Handler添加了一种新的类型,那么所有HandlerFactory实现都需要更改以拥有获取该类型的方法,HandlerPs 不需要更改。

用法看起来像

final P1 p1 = new P1();        
final DatabaseHandler<P1> databaseHandler = p1.getHandlerFactory().getDatabaseHandler();

因此,您可以从该实例获取该实例的特定数据库处理程序。

于 2013-03-26T01:18:59.007 回答