★实例:
◎◎需求:
设计一个图书馆管理系统(部分),可以借出图书和CD,但是不能借出期刊。
◎◎设计:
▲ 方案一(见图片1):
Book和CD具有的类型BorrowableItem,Jounal具有类型NonBorrowableItem。这似乎是完美合理的,而且是图书馆系统常用的解决方案。
这个解决方案可以工作,但这不是非常优美的,它混合了类Library的两种不同的考虑:
l 馆藏对象;
l 借出对象;
▲ 方案二(见图片2):
针对方案一的问题,我们对该模型稍微进行改进,引入了新类LibraryItem,在继承层次上添加额外的层次。在继承层次中,我们把“可借出”协议放在独立的层次上。这是这类问题的通用解决方案。
问题是:Book和CD具有可借出的这种能力,但是却存在问题:BorrowableItem具有可以完全说明类Book和CD的能力吗?
可借出能力可能只是它们行为的某个特征的方面,而这种行为碰巧在图书馆系统的语境中具有共性。从语义上看,把BorrowabelItem看作类Book和CD同Library交互所扮演的特定角色更加合适,而不是把BorrowabelItem看作类Book和CD的超类。
▲ 方案三(见图片3):
该方案中,我们引入了接口提供更加优美的解决方案。
基于接口解决方案的好处如下:
1. Library中的每个物品都是LibraryItem――这很直观;
2. 我们把“可借出性”分离为独立的接口Borrowable,只要需要,我们可以把它用于LiraryItem;
3. 我们具有更少的类――5个类和1个接口,方案二却有7个类;
4. 我们具有更少的关联――1个组合关系,3个继承关系,方案二却有2个组合关系,5个继承关系;
5. 我们具有更加简洁的继承层次,2层;
总之,基于接口的解决方案更加简洁、灵活并且语义更好。
///////////////////////////////////////////////////////////////////////
比如假定你需要把Book和Journal的详细资料输出为CSV文件。我们设计的解决方案如下:
l 引入类CSVExporter执行XML输出;
l 引入接口CSVExportable,它定义了每个可输出物品同类CSVExporter工作的协议;
我们可在Book和Jounal类中引入CSVExporter接口来实现文件输出需求。
///////////////////////////////////////////////////////////////////////
借助该解决方案,我们可以独立管理可馆藏性(组合关系)、可借出性(接口Borrowable)和可输出性(接口XMLExportable)。
★总结:
◆接口实现的语义是“实现由…指定的契约”。
◆继承的语义是“是一种…”。
一些类通常不应该通过继承进行关联,使用接口指定这些类的通用协议会使解决方案更加简洁、灵活和优美。
- 大小: 9.2 KB
- 大小: 10.4 KB
- 大小: 10.2 KB
分享到:
相关推荐
### 浅谈Java集合框架 Java集合框架是一个用于存储、操作和检索一组对象的强大工具集。集合框架的设计目的是为了提供一套高效且灵活的数据结构来满足不同的应用需求。本篇文章将详细探讨Java集合框架中的一些核心...
JavaScript是一门面向对象的脚本语言,其对象和继承机制与传统面向对象语言(如Java和C++)存在显著差异。JavaScript的对象不是基于类的实例,而是通过构造函数或者字面量创建的。JavaScript的对象可以被视为键值对...
JDK动态代理的局限性在于,它只能为实现了至少一个接口的类创建代理,因为代理对象必须继承自这些接口。这种方式适用于那些基于接口进行编程的设计,比如Spring AOP中的Advisor和Advice。 相反,CGLIB(Code ...
- 实现接口时,必须提供接口中所有方法的实现,除非接口继承自另一个接口,且那些方法已被其他接口或父类实现(对于抽象类)。 - 接口中的方法默认是抽象的,但 Java 8 引入了默认方法,可以在接口中提供默认实现...
如果一个类、接口或方法被声明为`public`,那么它可以在程序的任何地方被访问。 - `protected`: 受保护的,可以被同一包内的类和不同包中的子类访问。这在设计继承结构时非常有用。 - `default`: 没有明确的访问...
标题《浅谈Javascript面向对象编程》涉及了JavaScript语言在实现面向对象编程(OOP)方面的核心概念及其灵活运用。接下来,我们详细地梳理一下从给定文件内容中提取的关于JavaScript面向对象编程的知识点。 1. 数据...
- **虚继承**:为了解决菱形继承中多个父类实例的同一成员可能出现在不同位置的问题,引入虚基类,确保只有一个副本。 2. **成员变量和成员函数的访问**: - **成员变量**:非静态成员变量占据类实例的内存,而...
- **多重继承**:如果一个类从多个基类继承,子类实例会包含所有基类的实例,可能涉及二进制对齐和偏移调整。 - **虚继承**:解决多重继承中的菱形继承问题,引入虚基类,确保只有一个基类实例,减少内存消耗和...
C++对象模型是C++编程中的一个重要概念,它涉及到C++类的内存布局、成员变量的访问方式、成员函数的实现、以及与VC++编译器相关的特定细节。理解对象模型有助于提升C++程序员的技术水平,尤其是在调试、优化和使用...
与 `__dict__` 不同,`dir()` 函数返回的是一个包含所有属性名称的列表,包括实例方法、类方法、静态方法以及其他从基类继承的属性。`dir()` 函数不仅适用于实例,也适用于类。下面来看一个使用 `dir()` 的示例: `...
### 浅谈Python新式类与旧式类的区别 #### 引言 Python作为一种动态类型的高级编程语言,自诞生以来经历了多个版本的迭代更新。在这些版本中,Python 2.2 版本是一个重要的转折点,因为它引入了一个新的概念——...
继承允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码的复用。多态则指同一个方法在不同对象上可能有不同的表现形式。 在Java中,类的定义通常如下所示: ```java class 类名 { 访问修饰符 ...
在代码中,`CompositeUnit` 类作为组合类,继承自 `Unit`,并且包含了一个 `$units` 数组,用于存储多个 `Unit` 类的实例。这样,`CompositeUnit` 不仅代表单个军事单位,还能表示由多个单位组成的军队。 `...
`equals()` 方法是 `Object` 类的一个方法,所有类都默认继承了 `Object` 类,因此所有对象都有 `equals()` 方法。在 `Object` 类中,`equals()` 默认行为与 `==` 相同,即比较对象的引用。但许多类(如 `String`、`...
问题的出现可能与Django的不同版本有关,因为不同版本的Django可能对处理相同键的多个值的方式有所差异。例如,在某些版本中,即使只有一个值,`QueryDict`也可能返回一个单元素的列表。这种行为的不一致性可能导致...
继承是另一个重要的面向对象特性,允许一个类(子类)继承另一个类(父类)的属性和方法。Java使用`extends`关键字表示继承,重写方法时要求方法名、返回值类型、参数相同,且访问修饰符至少与父类方法相同。子类...
- **基础类与衍生类-谈继承(Inheritance)**:介绍了类继承的概念。 - **this指针**:解释了`this`指针的用途和意义。 - **虚函数与多态(Polymorphism)**:探讨了虚函数和多态性的实现。 - **类与对象大解剖**:...
- `sealed`修饰类,禁止其他类继承它,与Java的`final`类类似。 总结,`final`、`const`和`readonly`都是用来保证变量或对象的不可变性,但它们在不同的上下文和时机有不同的应用和限制。理解这些关键字的差异有助...