目录
CRP原则
复合重用原则
- 类应该通过其组合(通过包含实现所需功能的其他类的实例/委托)而不是从基类或父类继承来实现多态行为和代码重用
- 组合一个对象所能做的事(has_a or use_a)比扩展它所能做的事(is_a)要好。
eg1.计算不同类别员工的年终奖
//通过继承
class Employee{
Money computeBonus(){...//default computation}
}
//不同类别的员工
class Manager extends Employee{
@Override
Money computeBons(){...//special computation}
...
}
...
//不同类型的manager
class SeniorManager extends Manager{
@Override
Money computeBons(){...//more special computation}
...
}
存在的问题:
- 更改某个manager的类型时如何处理?
- 如果两个类型的计算方式一样时,如何处理?复制?
- 每个Employee对象的奖金计算方法都不同,在object层面而非class层面
A CRP solution:
class Employee{
BonusCalculator bc;
...
}
|
|Delegation
|
V
interface BonusCalculator{
Money computeBonus();
}
//Inheritance:继承
class Manager extends Employee{
Money computeBonus(){
bc=new ManagerBonusCalculator();
return bc.computeBonus();
}
}
|
|Delegation
|
V //Implement:接口实现
class ManagerBonusCalculator implements BonusCalculator{
Money computeBonus{...//special computation}
}
接口的组合
接口之间通过extends实现行为的扩展
接口的组合,定义了行为的组合
白盒框架的原理与实现
白盒框架:通过代码层面的继承进行框架扩展
- 通过继承和动态绑定实现可扩展性
- 通过子类化(subclassing)和重写方法进行扩展
- 通用设计模式:模板方法
- 子类有main方法,但控制框架(gives control to framework)
public abstract class PrintOnScreen{
//main body of framework reuse
public void print(){
JFrame frame=new JFrame();
JOptionPane.showMessageDialog(frame,textToShow());
frame.dispose();
}
//extension point
protected abstract String textToShow();
}
public class MyApplication entends PrintOnScreen{
@Override
protected String textToShow(){
return "printing this text on"
+"screen using PrintOnScreen"
+"white Box Framework";
}
}
MyApplication m=new MyApplication();
m.print();
黑盒框架的原理与实现
黑盒框架:通过实现特定的接口/delegation进行框架扩展
- 通过可插入框架的组件定义接口来实现可扩展性
- 通过定义符合特定接口的组件来重用现有功能
- 通过实现插件接口进行扩展
- 常见设计模式:策略、观察者
- 这些组件通过委托与框架集成
- 插件加载机制(Plugin-loading mechanism)加载插件并控制框架
public final class PrintOnScreen{
TextToShow textTOShow;
public PrintOnScreen(TextToShow tx){
this.textToShow=tx;
}
public void print(){
JFrame frame=new JFrame();
JOptionPane.showMessageDialog(frame,frame.dispose());
}
}
public interface TextToShow{
String text();
}
public class MyTextToShow implements TextToShow{
@Override
public String text(){
returong "Printing";
}
}
PrintOnScreen m=new PrintOnScreen(new MyTextToShow());
m.print();
设计模式
设计模式更强调多个类/对象之间的关系和交互过程–比接口/类复用的粒度更大
adapter/适配器模式
将某个类/接口转换为client期望的其他形式
- 解决类之间接口不兼容的问题
- 通过增加一个接口,将已存在的子类封装起来,client面向接口编程,从而隐藏了具体类。
eg。
//without Adaptor pattern
class LegacyRectangel{
void display(int x1,int x2,int w,int h){...}
}
class Client{
public display(){
new LegacyRectangle().display(x1,y1,x2,y2);//没有办法兼容
}
}
interface Shape{
void display(int x1,int y1,int x2,int y2);
}
class Rectangle implements Shape{
void display(int x1,int y1,int x2,int y2){
new LegacyRectangle().display(x1,y1,x2-x1,y2-y1);
}
}
class LegencyRectangle{
void dispalynew(int x1,int y1,int w,int h);
}
class Client{
Shape shape=new Rectangle();//与LegacyRectangle隔离
public display(){
shape.display(x1,y1,x2,y2);
}
}
decorator/装饰器模式
- 为对象增加不同侧面的特性
- 对每一个特性构造子类,通过委派机制增加到对象上
以递归的方式实现
装饰器模式use both继承机制和委托机制
- 接口:定义装饰物执行的公共操作
- 起始对象,在其基础上增加功能(装饰),将通用的方法放到此对象中
- Decorator抽象类是所有装饰类的基类,里面包含的成员变量component指向了被装饰的对象
eg。
public interface IceCream{//顶层接口
void AddTopping();
}
public class PlainIceCream implements IceCream{//基础实现,无添加的冰激凌
@Override
public void AddTopping(){
System.out.println("Plain IceCream ready for some toppings!");
}
}
/*装饰器基类*/
public abstract class ToppingDecorator implements IceCream{
protected final IceCream input;
public ToppingDecorator(IceCream i){
this.imput=i;
}
public abstract void AddTopping();//留给具体装饰器实现
}
public class CandyTopping extends ToppingDecorator{
public CandyTopping(IceCream i){
super(i);
}
public void AddTopping(){
input.AddTopping();
System.out.println("Candy Topping added!");
}
}
public class NutsTopping extends ToppingDecorator{
//similar to CandyTopping
}
public class PeanutTopping extends ToppingDecorator{
//similar to CandyTopping
}
public class Client{
public static void main(String[] args){
IceCream a=new PlainIceCream();
IceCream b=new CandyTopping(a);
IceCream c=new PeanutTopping(b);
IceCream d=new NutsTopping(c);
d.AddTopping();
//or
Icecream toopingIceCream=
new NutsTopping(
new PeanutTopping(
new CandyTopping(
new PlainIceCream())));
toppingIceCream.AddTopping();
}
}
//The result:
//Plain IceCream ready for some toppings!
//Candy Topping added!
//Peanut Topping added!
//Nuts Topping added!
façade/外观模式
客户端需要一个简化的接口来访问复杂系统内的功能
- 提供一个统一的接口来取代一系列小接口调用,相当于对复杂系统做了一个封装,简化客户端使用
- 便于客户端学习使用,解耦
eg。
查看实例的详解
strategy/策略模式
有多种不同的算法来实现同一个任务,但需要client根据需要动态切换算法,而不是写死在代码里。
为不同的实现算法构造抽象函数,利用delegation,运行时动态传入client倾向的算法实例
template/模板模式
做事情的步骤一样,但具体方法不同
共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现
模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现
使用继承和重写实现模板模式,模板模式在框架(白盒框架)中广泛使用。
iterator/iterable(迭代器模式)
客户端希望遍历被放入容器/集合类的一组ADT对象,无需关系容器的具体类型
也就是说,不管对象被放进那里,都应该提供同样的遍历方式。
Iterable接口:实现该接口的容器对象是可迭代遍历的
public interface Iterable<T>{
...
Iterator<T> iterator();//返回一个迭代器
}
Iterator接口:迭代器
public interface Iterator<E>{
boolean hasNext();
E next();
void remove();
}
Iterator pattern:让自己的集合类实现Iterable接口,并实现自己独特的Iterator迭代器(hasNext,next,remove),允许客户端利用这个迭代器进行显示或隐式的迭代遍历:
for(E e:collection ){...}
Iterator<E> iter=collection.iterator();
while(iter.hasNext()){...}
eg.
public class Pair<E> implements Iterable<E>{
private final E first,second;
public Pair(E f,E s){first=f;second=s;}
public Iterator<E> iterator(){
return new PairIterator();
}
}
private class PainIterator implements Iterator<E>{
private boolean seenFirst=false,seenSecond=false;
public boolean hasNext(){return !seenSecond;}
public E next(){
if(!seenFirst){seenFirst=true;return first;}
if(!seenSecond){seenSecond=true;retun second;}
throw new NoSuchElementException();
}
public void remove(){
throw new UnsuppportedOperatinException();
}
}
Pair<String> pair=new Pair<String>("foo","bar");
for(Strig s:pair){...}