Java 实现和 UML 规范 wrt 接口和抽象之间的区别 类

Difference between Java implementation and UML specification wrt interfaces and abstract classes

存在各种类似的问题,但我可以找到 none 来回应我的 query.The 在实现接口时具有指定聚合关系的可能性是我的问题的重要组成部分,这是未在其他类似问题或其解决方案中处理。

我的问题涉及 Java 中设计模式的实现。为了便于解释,我正在考虑如图所示的命令设计模式。

由于这个UML表示要求"Invoker"应该是一个接口,而且还应该和"Command"接口有一个N元聚合关系,所以如果我定义是实现不了的调用者作为 Java 接口,因为我不能在 Java 接口中声明 non-static non-final 属性,我确实需要定义一个 non-final Collection of "Command" 对象建立 "Invoker" 和 "Command" 之间的聚合关系。

因此,我继续将 Invoker 实现为一个抽象 class,这让我可以进行聚合并为 "Invoker" 的实现提供抽象,但我想知道它是否是一个良好的设计实践,因为 UML 确实有构造型 <<abstract>>,但此模式的 UML class 图明确指定使用接口而不是抽象 class。 出于类似的原因,我也为 Java 中 "Observer" 模式实现的 "Subject" 接口做了同样的事情。

请告诉我是否有办法在Java中保持"Invoker"作为一个接口并且仍然实现具有指定多重性的聚合关系。 如果我所做的是最好的方法,请告诉我它是否会对我使用这种模式构建的程序的结构产生一些不利影响。

在 class 图表下方添加命令模式的简短 Java 实现,我提出了该图表以提高问题的清晰度。我在这里配置 "Controller" 作为 "Invoker" 接口,可以用不同的方式实现,例如"InfraredRemote Controller" 在此图中。但是 "Invoker" 和 "Command" 接口之间聚合关系的设计模式要求让我将 "Controller" 配置为抽象 class 因为我找不到任何方法来实现所需的多样性和当我将 "Controller" 配置为接口时的关系。

命令模式中的重要部分是所有 ConcreteCommand 都有一个共同的 Command "interface" 隐藏了整个命令逻辑以及所有可能的 Receiver。这将一堆代码变成一个对象,任何人都可以在不了解系统其余部分的情况下执行。依赖倒置原则中的依赖方向在这里很重要。

我什至不认为实现此模式的硬性要求是使用 interface 实现 Command "interface" .关键是需要有一些隐藏细节的东西。如果您针对要在 Java 中实现的具体问题进行具体的 UML 系统设计,并将命令标记为 <<interface>>.

,则情况不同。

CommandInvoker 之间的关系也不是真正的调用者 "interface"(-contract) 的一部分。客户不应该关心。它只是看到它可以传递命令。 n 元聚合的目的可能是表明调用者可以采用任何种类/数量的 CommandsCommands 或多或少在该模式之外的事物的描述 & 为 Client 所知(该关系也不是必需的,命令可以以某种方式找到一些调用者比较 this).该模式本身并不要求 Invoker 是一个 interface。它可以是具体的,因为具体的实现仍然有一个 "interface".

命令模式的一个常见应用是拥有一个调用程序来跟踪应用的命令并允许撤消它们,例如。在那种情况下,具体调用程序和命令之间存在很强的关系,其中调用程序将命令存储在列表的某个列表中。该图也可能意味着这一点。通常在模式图中根本没有这种关系。再次参见上面的 link。

不管这意味着什么,我会说你不应该在 Invoker 中实现 CommandInvoker 之间的具体关系,以防你决定 Invokerinterface。这将比这张图显示的要多。它还将强制所有调用者具有特定的行为。这不是这个模式的重点。

<<interface>><<abstract>> 刻板印象只有在设计图表的人实际上意味着 Java 等效时才有意义。当图表显示一个概念时,任何不相关的东西都会成为一个界面,这通常不是这种情况。这同样适用于关系。 "Aggregation" 可以很自由地使用。在调用者<>命令关系的情况下这可能意味着调用者已经看到了所有的命令,它不必存储它们。

多亏了与@zapl 的良好集思广益 session 以及对网络的更多研究,我通过一本非常有趣的书的 this article that makes reference to this 页找到了答案。

“Program to an interface”, really means “Program to a supertype”. – Head First, Design Patterns

显然,在设计模式的 UML 规范中使用单词 'Interface' 更通用,仅表示抽象,即。超类型,可以通过使用接口或抽象 class 在 Java 实现中实现。尽管 UML 中存在 <<abstract>> classes 的构造型,但它们很少用于描述设计模式。

并且由于无法在 Java 接口之间实现 n-ary 多重性,因此我在问题中使用的示例中的 UML "Invoker" 接口需要使用 Java 接口由抽象 class 实现,并通过使用具体的 Invoker subclass 扩展该抽象 class 。这将保持代码的可塑性,同时保留抽象,如下面的实现所示:

这里客户端"Implementer"使用Java接口,它由Java抽象class实现,以提供"Command"接口的多样性和访问具体调用者的多样性;这两个一起代表命令设计模式的UML规范中的"Invoker"接口。

我现在将我的回答留待评论,期待对我可能错过的事情发表评论。如果我没有收到,我会在两天内接受我的答复。