设计:解决这个问题的最佳方法?

时间:2013-03-26 01:00:19

标签: java oop

到目前为止,我已多次解决这个设计问题,并且我总是通过以下方式解决它。但是,我只是想知道这是否是正确的方法,或者是否有更好的方法。该语言是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的铸造。具体的PHandler知道他们想要在编译时处理它们的类型。为什么要等到运行时? (它是一种Java语言限制,可以通过双重调度等任何技术来避免?无法理解它)

第二,工厂违反了开放原则 - 原则。我通常通过reflection / properties文件来实现它以避免OCP。编辑:当我们继续添加更多P的实例时,我们需要不断更改工厂(除非使用反射)

我还在Concrete P实现上使用了Annotations。同样,它违反OCP,更糟糕的是,P可以有不同类型的处理程序,具有不同的目的。

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

2 个答案:

答案 0 :(得分:2)

正如@ bmorris591所说,“仿制药是整理它的方法”。但这可能只是因为你的例子很简单,就这样做了。

这实际上取决于背景。编写代码的方式让我想起了the visitor pattern。这是双重调度的一种方式。它有一些优点和缺点。最大的问题是它会使代码复杂化。

在某些情况下,你使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实现中是没有意义的。这完全取决于背景。

答案 1 :(得分: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访问您的PVisitor实例,并且多态将找出您的内容。

修改

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

抽象工厂模式与访客模式和一些泛型相结合。

我们知道,如果我们添加新类型Handler,那么需要更改某些内容 - 逻辑上它应该是HandlerFactory实现而不是P。如果我们有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继承的P1BP1仅使用P1Handler,如果它们不需要任何更改。

如果添加了新类型的Handler,则需要更改所有HandlerFactory实现,以获得获取Handler类型的方法,但P s不需要改变。

用法看起来像

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

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