【问题标题】:Design pattern to delegate different operations to different classes将不同操作委托给不同类的设计模式
【发布时间】:2014-07-24 08:33:17
【问题描述】:

我有一个 ABC 类,它可以执行操作 a()、b() 和 c()(操作 == 方法),它们都密切相关。我也有类似的 DE 和 FGH 类。将来,可能会添加带有其他操作的新类。类从不共享操作(例如,没有类 ADF)

我的程序应该能够执行所有这些操作,而且时间是“随机的”,这意味着我事先没有估计什么时候/多少次执行哪个操作。

我通过创建一个包装类“OperationInvoker”来处理这个程序。我的程序只能访问此调用程序,并且每个操作都有一个方法。这样做的好处是封装:如果创建了新操作或现有操作或编辑了新操作,则只有包装类需要编辑。

我的问题是“巨大的”包装器是否是解决这个问题的最佳模式?

我为此研究了观察者模式,我认为这不是一个合适的案例,因为 ABC、DE、FGH 类......从来没有任何共同利益。比如,如果需要执行操作 A,所有注册的类都会收到事件 A,只有 1 个类(即 ABC)会对这个事件真正感兴趣。所有其他注册的类都将丢弃该事件。这似乎是所有注册和观察的过度杀伤/开销。

委托模式也遇到了同样的问题:我没有很多类以不同的方式执行相同的操作,因此拥有灵活的委托系统毫无意义。

还有其他更好的模式吗,或者这只是拥有委托包装类的简单案例?

编辑:有人问 ABC 到底是做什么的。好吧,我有一个描述 SOAP Web 服务的 WSDL 文件。我使用一个工具将此文件转换为 java 类。这意味着我无法控制这些类的内容,因为它们是自动生成的。所以我写了一个类 WebServiceInvoker 作为这些 Web 服务的包装器。这个包装类有 3 个方法:做 Web 服务 A、做 Web 服务 B 和做 Web 服务 C。

随着程序的扩展,越来越多的wsdl文件进入画面。当然,没有一个 Web 服务做同样的事情。它们没有全部捆绑在一个大 wsdl 文件中的唯一原因是因为某些 Web 服务在逻辑上不属于其他 Web 服务。所以我结束了以下课程:

  • 一个可以调用Web服务A、B和C的封装类
  • 一个可以调用Web服务D、E的封装类
  • 一个可以调用webservice F、G、H的封装类

将来可能会出现更多 wsdl(以及包装类)。之所以在所有其他包装器周围有一个附加包装器,是因为每个服务都需要使用“会话 ID”来调用。所以每个包装器都需要知道这些信息。所以 superwrapper 持有这些信息,并且可以调用所有的 web 服务。这也作为一个 api 工作得很好:使用 Web 服务的程序对服务一无所知,它只有一个通过超级包装器可用于每个 Web 服务的公共方法。该程序当然知道每个 Web 服务返回什么(一个列表、一个字符串、什么都没有……)。

【问题讨论】:

  • 您想抽象出 ABC 和 DE 由单独的对象提供的事实吗?如果是这样,包装器似乎不错。如果客户端知道 ABC 和 DE 是分开的没问题,为什么不直接将它们传入(构造函数注入),可能使用接口 IABC 和 IDE?
  • 所有操作都需要一个共享参数:调用操作的用户名。包装类似乎是存储此用户名的理想场所。我真的不需要我的程序不知道 ABC 和 De 是否分开,但我认为这也没有什么坏处(关注点分离)。
  • 在我看来,ABC、DE 和 FGH 类正在做非常不同的事情。那么共享处理真的有用吗?假设您有 Car、House 和 Pizza 类。一起处理它们是个好主意吗?或者,如果您只是区分这些类并单独处理每个类,会不会更容易?好吧,这只是我的想法。
  • 另一种适合的模式是使用代理,甚至可能是proxy extending a class
  • @Korashen:每个操作都是一个网络服务。每个 Web 服务都有一个共享部分(创建肥皂体,添加连接参数......)但每个服务也有很大不同(有些返回 ture/false,其他有更多复杂的响应,有些可能会抛出错误......)。应该一起处理吗?我觉得他们应该这样做。

标签: java design-patterns


【解决方案1】:

为了便于代码维护,我建议将包装器更改为如下内容:

public class Operations {
    private ABC abcInst;
    private DE deInst;
    private FGH fghInst;

    protected Operations(ABC abc, DE de, FGH fgh) {
        this.abcInst = abc;
        this.deInst = de;
        this.fghInst = fgh;
    }

    public ABC getABC() { return abcInst; }
    public DE getDE() { return deInst; }
    public FGH getFGH() { return fghInst; }
}

这种方式在这里不需要维护(除非添加了一个新类),并且来自调用者的所有调用只需要额外的.getABC().a() 而不是.a() 等。这强调了执行操作的事实通过不同的类,但仍然允许通过传递 Operations-instance 来访问所有功能。

【讨论】:

  • 在操作类中,返回 ABC 以便调用者可以执行 ABC.a() 与在调用 ABC.a() 本身的 allOps 中提供方法 a() 相比有什么优势?跨度>
  • @user1884155 如果将方法ab() 添加到类ABC 中,则无需更改Operations 中的任何内容。
【解决方案2】:

看起来你在一侧有一个明确的架构,你试图不泄露到其他组件中。避免此类泄漏的自然方法是增加一层分离度。

基本上,如果您愿意,您仍然可以保留一个巨大的包装器,但您需要考虑您希望公开的内容并仅公开它。看起来您想要公开的只是一个已知操作的列表,所以如何:

// Your setup - trimmed down.
interface ABC {

    public void a();

    public void b();

    public void c();
}

interface DE {

    public void d();

    public void e();
}

interface FGH {

    public void f();

    public void g();

    public void h();
}

// Your current wrapper.
class AllOps {

    public ABC getABC() {
        return null;
    }

    public DE getDE() {
        return null;
    }

    public FGH getFGH() {
        return null;
    }
}

// One further degree of separation.
enum Op {

    A {

                @Override
                void op() {
                    ops.getABC().a();
                }

            },
    B {

                @Override
                void op() {
                    ops.getABC().b();
                }

            },
    C {

                @Override
                void op() {
                    ops.getABC().c();
                }

            },
    D {

                @Override
                void op() {
                    ops.getDE().d();
                }

            },
    E {

                @Override
                void op() {
                    ops.getDE().e();
                }

            },
    F {

                @Override
                void op() {
                    ops.getFGH().f();
                }

            },
    G {

                @Override
                void op() {
                    ops.getFGH().g();
                }

            },
    H {

                @Override
                void op() {
                    ops.getFGH().h();
                }

            };
    // Hide the huge wrapper.
    private static AllOps ops = new AllOps();
    // Only expose the operations.
    abstract void op();
}

public void test() {
    Op.A.op();
    Op.F.op();
}

不确定这是什么模式,但如果您只公开枚举,我认为您已经实现了断开连接。

可以以任何您喜欢的方式将其他操作添加为实现op 的新枚举。他们甚至可能不使用巨大的包装器。

【讨论】:

  • 在 allOps 类中,返回 ABC 以便调用者可以执行 ABC.a() 比在 allOps 中提供一个调用 ABC.a() 本身的方法 a() 有什么好处?跨度>
  • @user1884155 - 根本没有 - 该代码旨在演示一种增加进一步断开程度的技术。我以您的包装器为例,该技术显然可以很容易地使用这三种类型中的一种,并且从用户的角度来看仍然没有变化 - 从而证明了断开连接的价值,它的实现可以在不影响它的情况下更改界面。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-02
  • 1970-01-01
  • 2015-08-02
  • 2011-10-24
  • 2019-12-20
相关资源
最近更新 更多