- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我知道有一个类似的问题 here .它考虑了比我在这里的问题更通用的类特定行为问题。
考虑以下复合模式的简单实现:
interface Item {
int getWeight();
}
class SimpleItem implements Item {
private int weight;
public int getWeight() {
return weight;
}
}
class Container implements Item {
private List<Item> items;
private int weight;
public void add(Item item) {
items.add(item);
}
public int getWeight() {
return weight + items.stream().mapToInt(Item::getWeight).sum();
}
}
现在考虑 Item 的用户如何确定它是否是一个容器。例如,Container pushAdd
中需要一个方法,该方法将一个项目向下推到一个没有容器的容器中。容器只知道项目,它不知道这些项目是容器还是简单项目或其他实现项目的类。
存在三种可能的解决方案:
1.使用和类型转换的实例
public void pushAdd(Item item) {
Optional<Container> childContainer = items.stream()
.filter(item instanceof Container)
.map(item -> (Container)item)
.findAny();
if (childContainer.isPresent()) {
childContainer.get().pushAdd(item);
} else {
add(item);
}
}
2。实现 is/as 方法
public pushAdd(Item item) {
Optional<Container> childContainer = items.stream()
.filter(Item::isContainer)
.map(Item::asContainer);
....
}
3。访问者模式(我省略了简单的 accept
实现)。
interface ItemVisitor {
default void visit(SimpleItem simpleItem) { throw ...}
default void visit(Container container) { throw ... };
}
public pushAdd(Item item) {
Optional<Container> childContainer = ... (using instanceOf);
if (childContainer.isPresent()) {
childContainer.get().accept(new ItemVisitor(item) {
void visit(Container container) {
container.pushAdd(item);
}
};
} else {
add(item);
}
}
第一个是邪恶的,因为它使用了 instanceof 和转换。第二个是邪恶的,因为它将 Container 的知识强加到 Item 中——当创建了 item 的其他子类时,情况会变得更糟。第三个不会帮助您知道在调用访问者之前是否可以添加到项目中。您可以捕获异常,但对我来说这似乎是对异常的滥用:最好有一种在访问前进行检查的方法。
所以我的问题是:是否可以使用另一种模式来避免转换和 instanceof,而不必将子类的知识推到层次结构中?
最佳答案
当我说访问者模式在 Java 中并不流行时,我想我代表了所有 Java 人。所以上面可以这样实现(我将在这里使用接口(interface),因为根据我的经验,它们更灵活):
interface Item { /* methods omitted */ }
interface SimpleItem extends Item { /* methods omitted */ }
interface ContainerItem extends Item { /* methods omitted */ }
// telling clients that this can throw an exception or not
// here is a whole different design question :)
interface ItemVisitor { void visit(Item i) /* throws Exception */; }
class MyVisitor implements ItemVisitor {
void visit(Item i) {
if (i instanceof SimpleItem) {
// handle simple items
} else if (i instanceof ContainerItem) {
// handle containers using container specific methods
} else {
// either throw or ignore, depending on the specifications
}
}
}
instanceof
的成本在最新的 JVM 上非常低,所以我不会太担心,除非你能证明传统的访问者要快得多。
代码的可读性和可维护性可以说是相同的,只有一些差异。首先,如果将新界面添加到层次结构中,不会修改现有访问者,则不需要更改这些访问者。另一方面,更容易忽略确实需要更改的访问者(尤其是在您无法控制的客户端代码中),因为访问者没有明确要求客户端这样做,但是,嘿,这就是维护代码的本质和需要访问的设计的一般缺点。
这种模式的另一个优点是不需要访问的客户端不需要担心它(没有 accept
方法),即更短的学习曲线。
最后,我认为这种模式更接近于“纯粹的”OOD,因为接口(interface)层次结构不包含虚假方法(visit
、canAddItems
等。 ), 即有 no "tags"各种各样的。
关于java - 使用复合类 : how a client can determine whether it is composite,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27853657/
我正在开始开发一个使用 JSF 2 作为 View 技术的新 Web 应用程序。 我之前没有使用 JSF 的经验,对这些概念有点困惑。 我阅读了一些关于 JSF 的文档,主要思想是它是一个基于组件的框
我试图找出这是一个 JSF/EL 问题还是这里出了什么问题。 基本上,我想将项目对象作为 ui:param 传递给 ui:composition 并在里面有一个按钮(即引导按钮,因此它们实际上是 ht
我是 GWT 的新手,正在尝试制作一个简单的应用程序(例如 fmylife 的小型版本)。到目前为止,我制作了一个加载事实的复合 Material 和另一个具有提交新事实的表单的复合 Material
我对 Agda 很陌生,我正在尝试做一个简单的证明“ map 的组合就是组合的 map ”。 (来自 this course 的练习) 相关定义: _=$=_ : {X Y : Set}{f f' :
我有三个组合(compFinal、compSlide1 和 compSlide2)。 我已经使用脚本将 compSlide1 和 compSlide2 添加到 compFinal 组合中。 我使用以下
我有以下情况: #{cc.attrs.someValue} 因此,在我的复合组件中,我正在调用其他一些复合组件,并尝试将提供给“主”复合组件的参数
我正在尝试使用 Constraint composition并希望为每个复合约束定义组,如下例所示:- 复合约束 @Target({ ElementType.FIELD, Elemen
尝试使用 Jetpack Compose 显示 AlertDialog,但应用程序在调用 AlertDialog 函数时崩溃,错误为 java.lang.IllegalStateException:
我想根据按钮的可见性属性重绘组合中的按钮。我根据其中的按钮进行合成以调整大小,并且我正在使用以下代码来刷新合成。问题:下面的代码工作正常,但按钮从未在复合中重新定位请帮忙。代码中是否缺少要重新定位的内
我正在研究 After Effects 脚本并使用 AE 脚本指南作为学习基础。 我有一个 After Effect 项目,其中包含两个 AE 项目,并且每个项目中都有多个项目。 我想从具有特定名称的
我一直在学习如何在 python 编程中实现组合,但我很难理解为什么它比继承更受欢迎。 例如,这是迄今为止我的代码: class Particle: # Constructor (public)
概述 是一种结构型模式,将对象以树形结构组织起来,以表示“部分 - 整体”的层次结构,使得客户端对单个对象和组合对象的使用具有唯一性。 UML类图 上面的类图包含的角色: Compone
我们已经尝试去定义类。定义类,就是新建了一种类型(type)。有了类,我们接着构造相应类型的对象。更进一步,每个类型还应该有一个清晰的接口(interface),供用户使用。 我们可以在一个新类的
一、Options API的弊端 Options api的一大特点就是在对应得属性中编写对应的模块。比如data定义数据、methods中定义方法、computed中定义计算属性、watch中监听属性
我正在使用 SWT ScrolledComposite,但是当我在 Windows 中滚动时,如果我快速滚动,我会出现一些撕裂/闪烁。我该怎么做才能加倍缓冲或减少这种影响,或者我该怎么做才能覆盖默认滚
在 JSP 和 JSTL 中我通常会做这样的事情: ${user.name} ${user.description}
几周以来,我们的 Web 应用程序出现了性能问题。首先我们认为问题属于大 DOM。大 DOM 并不是很好,但这不是主要的性能问题。 问题在于复合组件。过去几周,我们开发了核心复合组件,以减少代码冗余并
如何在 mySQL 中创建复合主键。在 table1 中,我需要将 id1、id2 设置为复合主键。我使用了这个查询。但它使每个成为主键。它检查每个条目的重复项 ALTER TABLE `table1
我是 Java 的新手,我想将背景图像添加到 Composite。我只能使用 SWT,不能使用 JFace。我正在使用 eclipse indigo IDE (3.8),当我想设置背景图像时,首先我将
我有一个程序必须使用复合键来管理对象。这个键,简单来说就是几个字符串。 我有以下代码: public struct MyKey { public string Part1 { get; set
我是一名优秀的程序员,十分优秀!