§ Designing reusable classes 设计可复用的类
马上要软件构造期末考试了,整理一下学习笔记
– Inheritance and overriding 继承与重写
– Overloading 重载
– Parametric polymorphism and generic programming 参数多态与泛型编程
– Behavioral subtyping and Liskov Substitution Principle (LSP) 行为子类型与
Liskov替换原则
– Composition and delegation 组合与委托
§ Designing system-level reusable libraries and frameworks 设计
可复用库与框架
– API and Library
– Framework
– Java Collections Framework
(an example)
How much are paid for reusing this asset? 复用的代价有多大?
– Cost to buy the asset and other mandatory libraries 搜索、获取
– Cost for adapting and extending it 适配、扩展
– Cost for instantiating it 实例化
– Cost for changing other parts of the system that interact with it 与软件其他
部分的互连的难度
A software asset with high reusability should:
– Brief (small size) and Simple (low complexity)
小、简单
– Portable and Standard Compliance
与标准兼容
– Adaptable and Flexible
灵活可变
– Extensibility
可扩展
– Generic and Parameterization
泛型、参数化
– Modularity
模块化
– Localization of volatile (changeable) design assumptions 变化的局部性
– Stability under changing requirements
稳定
– Rich documentation
丰富的文档和帮助
White box reuse 白盒复用:源代码可见,可修改和扩展
– Reuse of code when code itself is available. Usually requires some kind of
modification or adaptation 复制已有代码到正在开发的系统,进行修改
– Pro: You can customize the module to fit the specific situation, this allows
reuse in more situations 可定制化程度高
– Con: You now own the customized result, so it adds to your code
complexity. You requires intrinsic knowledge on component internals. 对其
修改增加了软件的复杂度,且需要对其内部充分的了解
§ Black box reuse 黑盒复用:源代码不可见,不能修改
– Reuse in the form of combining existing code by providing some “glue”,
but without having to change the code itself - usually because you do not
have access to the code 只能通过API接口来使用,无法修改代码
– Pro: Simplicity and Cleanliness 简单,清晰
– Con: Many times it is just not possible 适应性差些
委托和继承
首先明确,这两种模式提出的初衷都是为了提高代码的可复用性,而在具体实现上有所不同。
委托:一个对象需要另一个对象的功能,于是捕获该对象,并发送到另一对象中进行功能调用。
继承:获得一个基类的元素和方法。
举个例子:水果需要工厂进行榨汁,而水果本身不具有榨汁的功能,将榨汁的行为写给水果也不合适,于是我们把水果交给工厂(类)中的方法进行处理,这是委托(delegation)。
水果具有下落(fall)的行为,苹果也有下落的行为,在水果(类)中写“下落”这种行为,然后在苹果(类)中通过extends获得这个方法的复用,这是继承(inheritance)
Composition(组合):将委托类完全内部化的delegation。
在这样的关系中,委托类的实例化,功能,生命周期均取决于被委托类的指派,委托类作为被委托类的一个private属性,且没有向外部提供更改该属性的方法(一般使用new 方法实例化之后便不再对其进行操作)。
两个类之间存在的关系为a-part-of.
Aggregation(聚集):将委托类作为内部属性的delegation。
• 在这样的关系中,委托类也为被委托类的内部属性,但是脱离了被委托类的使用(比如将被委托类释放),此时委托类仍然存在,并具有部分意义。
**
LSP
**
所有引用基类的地方必须能透明地使用其子类的对象。
1、里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。
2、里氏代换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。
3、里氏代换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。
§ 1、子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法;
§ 2、子类中可以增加自己特有的方法。
Subtypes can add, but not remove methods 子类型可以增加方法,但不可删
– Concrete class must implement all undefined methods 子类型需要实现抽象类型中的所有未实现方法
– Overriding method must return same type or subtype 子类型中重写的方法必须有相同或子类型的返回值或者符合co-variance的参数
– Overriding method must accept the same parameter types 子类型中重写的
方法必须使用同样类型的参数或者符合contra-variance的参数
– Overriding method may not throw additional exceptions 子类型中重写的方法不
能抛出额外的异常 子类型规约更强
§ Also applies to specified behavior (methods): 规约不变或更强
– Same or stronger invariants 更强的不变量
– Same or weaker preconditions 更弱的前置条件
– Same or stronger postconditions 更强的后置条件
– Preconditions cannot be strengthened in a subtype. 前置条件不能强化
– Postconditions cannot be weakened in a subtype. 后置条件不能弱化
– Invariants of the supertype must be preserved in a subtype. 不变量要保持
– Contravariance of method arguments in a subtype 子类型方法参数:逆变
– Covariance of return types in a subtype. 子类型方法的返回值:协变
– No new exceptions should be thrown by methods of the subtype, except
where those exceptions are themselves subtypes of exceptions thrown by
the methods of the supertype. 异常类型:协变 (This is to be discussed in
Section 7-2)
Generics are type invariant
– ArrayList is a subtype of List
– List is not a subtype of List
A与B有关系,Box(A)与Box(B)没有关系
继承 委托
如果子类只需要复用父类中的一小部分方法, 可以不需要使用继承,而是通过委派机制来实现,可以不用继承全部方法,只用委托机制调用部分方法.避免大量无用方法
§ Dependency: a temporary relationship that an object requires other
objects (suppliers) for their implementation.
§ 依赖:对象之间的动态的、临时的通信联系
–use a
Association: a persistent relationship between classes of objects
that allows one object instance to cause another to perform an action
on its behalf. 关联:对象之间的长期静态联系——has a
Composition组成: 更强的association,但难以变化
不同于一般的Association,这里变成了其一部分属性,并且彼此不可分,在
内部创建。
Aggregation: 更弱的association,可动态变化
has_a 对象存在于另一个对象之外,是在外部创建的,因此它作为参数传
递给构造函数。
聚合:部分与整体的关系,但彼此可分——owns a
In composition组合, when the owning object is destroyed, so are the
contained objects.
In aggregation聚合, this is not necessarily true.