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

Java 设计:解决这个问题的最佳方法?,java,oop,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 {

到目前为止,我已经多次遇到这个设计问题,我总是用下面的方法来解决它。然而,我只是想知道这是正确的方法还是有更好的方法。语言是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);
interface P
{
   void handle();
}

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

class P2 implements P {
   int p5; int p6;
   void handle () {...}
}
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.
    }
}
现在,这个代码从来没有让我完全满意

第一,我不喜欢混凝土浇筑的芬德尔。具体的幻影者知道他们要在编译时处理的类型。为什么要等到运行时?(这是Java语言的一个限制,任何技术都可以避免,比如双重分派?我无法理解)

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

我还对具体的p实现使用了注释。再次强调,它会破坏OCP,更糟糕的是,OCP可以有不同类型的处理程序,具有不同的目的

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

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

这真的取决于上下文。你编写代码的方式让我想起了。这是一种双重分派的方法。它有一些优点和缺点。最大的缺点是它会使代码复杂化

在某些情况下,您将p设为PHandler所希望的逻辑接口:

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);
interface P
{
   void handle();
}

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

class P2 implements P {
   int p5; int p6;
   void handle () {...}
}
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.
    }
}

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

如果您知道
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);
}
因此,您有一个访问者逻辑的
集合
,然后使用
PVisitor
访问
p
实例,多态性将计算出是什么

编辑

在OP的评论之后,我有了一个想法

抽象工厂模式与访问者模式和一些泛型相结合怎么样

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

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

这个想法是这样的:

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);
interface P
{
   void handle();
}

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

class P2 implements P {
   int p5; int p6;
   void handle () {...}
}
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.
    }
}

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

泛型是整理该实例的方法。不确定泛型有何帮助,因为我们的问题是运行时调度,而泛型在运行时不存在。有什么例子吗?
PHandler。。。无效句柄(T)
然后
P1Handler。。。无效句柄(P1)
类似的东西。我面前没有编译器,因此可能无法编译,但概念就在那里。谢谢,我明白了。它确实解决了强制转换问题。P主要是数据类,并且总是会有不同类型的处理程序。例如,DBHandler负责将P保存在db中。根据P的类型,它可以是OracleDbHandler或SQLDbHandler。PublishHandler将再次基于类型发布P。我们将使用HTMLPublishHandler或JMSPublishHandler。因此,将所有处理程序逻辑缠绕在具体的P实现中在这种上下文中是不起作用的。这听起来似乎符合访问者模式的工作方式。同样,你也可以用泛型来实现。如果你不能从访客模式中获得任何优势,我更喜欢后者。你是对的。当所有已知的混凝土P已知时,访客可申请避免浇筑。但问题是,当我们想要添加新的OCP实现时,PVisitor又会对OCP产生影响。在这种情况下,我宁愿让工厂成为紫罗兰OCP而不是访客。因为你可以写智能工厂来寻找幻影,避免OCP。谢谢分享这个想法。然而,我想知道你会选择哪种解决方案?我个人认为查找实现的简单工厂模式,在这种情况下,对于不同类型的处理程序,我们将有不同的handlerFactory。AbstractFactory为不同类型的处理程序引入了更多的耦合。这两种图案仍然是紫罗兰色的OCP。我不知道你们计划有多少种不同的处理者,所以我真的不能说。基本问题是,如果不想强制转换,那么需要在编译时了解类型——根据定义,需要进行耦合。依赖项注入框架可以在某种程度上解决这个问题,但是由于擦除的原因,您不能使用泛型,应该在何处注入什么也不完全清楚。