用于限制返回对象的可用方法的 Java 设计模式
Posted
技术标签:
【中文标题】用于限制返回对象的可用方法的 Java 设计模式【英文标题】:Java design pattern for limiting available methods for a returned object 【发布时间】:2012-02-01 02:27:32 【问题描述】:我是一名新的 Java/OO 程序员。我想创建一个方法(以下称为myMethod
),它根据检查输入参数和世界状态返回n 类型的对象之一。在这里说 n == 2 为简单起见:myMethod()
可以返回类型为 Foo
或 Bar
的对象。
Foo 和 Bar 有不同的方法可以调用它们,有些是专有的,有些是共同的,例如:
ReturnType? myMethod(inputs)
if (/*examining state of world & inputs implies a Foo*/)
return new Foo();
return new Bar();
...
public class Foo
public Foo()
public void x() ... //common to Bar
public void f() ...
public class Bar
public Bar()
public void x() ... //common to Foo
public void b() ...
对于myMethod()
以及类Foo 和Bar,我应该使用什么设计模式?如果我的方法的返回类型是 Foo 和 Bar 的超类(或聚合?),或者 Foo 和 Bar 实现了一些通用接口,那么有没有办法让从 myMethod()
接收对象的客户端能够安全地调用 @987654329 @ 或 b()
在返回的对象上而不需要使用对象自省或强制转换?
或者这种设计是一种反模式,我是否缺少明显的重写?谢谢。
【问题讨论】:
您描述的确切场景似乎没有意义-您的客户端代码无论如何都需要知道是调用“f”还是“b”,那么单次创建的优势是什么机制?听起来您的客户端代码会期望两个不同的对象在不同的代码路径中具有完全不同的行为。对于这三种行为(x、f 和 b)中的每一种,听起来您想要做的是 segregate interfaces。 Foo & Bar 都会实现 x 的接口,Foo 也会实现 'f' 等等 确实@val-akkapeddi 我目前有单独的接口“f”和“b”,它们是“x”的扩展,而 Foo 和 Bar 只实现了适当的扩展。然而,这似乎需要从被调用者进行强制转换,在我看来这是一个通用接口,除非重载,否则“f”和“b”会抛出异常,这将为被调用者带来更清晰的代码。 故意引发异常永远不会产生更简洁的代码 - 您将使用异常作为流程控制,调用错误的方法,然后尝试处理后果,而不是首先避免陷入这种情况 -对?在这种情况下,铸造也是令人讨厌和不必要的。我这样做的方法是拥有 Foo:Ix,If 和 Bar:Ix,Ib。您必须在代码中决定调用 f - 让该代码仅通过接口 If 引用其对象,并隐藏对 If、Ix、Ib 恕我直言的工厂方法后面的类的访问。 【参考方案1】:没有模式 - 知道类型和转换是无法做到的。
您必须将这些方法拉到公共接口或父类或强制转换。没有“模式”可以拯救你——这真是神奇的想法。
【讨论】:
Java 中是否有一种受欢迎的方法,或者这通常是特定于项目的风格?如果我做前者,如果有 Foo 的人试图调用aFoo.b()
,我可能会抛出异常,但是一旦 n 变大,通用接口就会抛出大量异常。然而,强制转换似乎给被调用者增加了更多的知识负担。
您可以编写工厂并返回接口或超类型的引用,但是您不能也不应该控制用户在拥有它后选择使用它做什么。它确实给被调用者增加了知识负担,但给设计者带来了更大的负担。被调用者应该处理他们给出的接口类型,而不需要强制转换。如果他们这样做了,你的设计就有缺陷。【参考方案2】:
在我看来,您正在寻找的设计模式是 Factory 设计模式,它在 OO 范例中非常常用。您可以阅读有关此模式的更多信息here。我不完全确定您想要实现什么,但我认为这种设计模式至少值得一看。
【讨论】:
Factory 是正确的——它将返回公共接口或超类类型的引用。但它不会帮助解决访问不在接口或超类型中的方法而不诉诸强制转换的问题。【参考方案3】:在 java 中,您可以对接口进行隐式向上转换,但必须使用显式向下转换,否则您的 java 将无法编译。
【讨论】:
【参考方案4】:看起来您正在尝试做的事情非常接近反模式。
由于返回的对象类型取决于“世界状态”,您是否希望调用方法检查返回对象的确切类型,并根据类型而有所不同?
我认为您需要坐下来,尝试解释此设计的用例是什么,然后也许我们可以帮助您提供更好的解决方案。
【讨论】:
遵循预期规范的被调用者会知道是否期望从 myMethod 返回 Foo、Bar 等,但如果被调用者犯了错误,我认为优雅地失败将引发异常。这里的调用方法用例是,在 GUI 自动化中,如果用户请求表单(Foo
),用户可以向 (f()
) 提供字符输入,但如果用户请求按钮(@ 987654323@) 用户不能提供输入,只能点击。 myMethod
是提供可自动化元素的联系人。
但是为什么该实现需要相同的方法来返回表单或按钮? - 现在在我看来,您需要一种方法让系统中的所有组件实现一个接口,该接口准确描述它们支持的输入类型,以及一种获得具有扩展功能的新接口的方法。这让我回到了:我不知道你到底要解决什么问题,但我很确定你的方法是错误的,所以试着坐下来,描述你正在尝试做的事情,而不是你的想法应该实施。
您自己的描述实际上是我想要实现的:) - 我认为 Val 上面的评论是我需要效仿的 - 我将尝试从调用方法,并删除myMethod()
作为一个整体的单点联系。以上是关于用于限制返回对象的可用方法的 Java 设计模式的主要内容,如果未能解决你的问题,请参考以下文章