复用的模式
创造模式
如何创建对象
结构模式
如何组合类和对象
- Adapter (适配器)
意图:将类的接口转换为客户端期望的另一个接口
– 解决类之间接口不兼容的问题
– 为已有的类提供新的接口
目标:对旧的不兼容组件进行包装,在新系统中使用旧 的组件
通过增加额外的间接层来解决不 协调/不兼容的问题。
简单点说就是一个类继承或实现或委托了两个及以上的类或者接口
- Decorator (装饰)
问题: 需要对对象进行任意或者动态的扩展组合
方案: 实现一个通用接口作为要扩展的对象,将 主要功能委托给基础对象(stack),然后添加功能(undo,secure,…)。 以递归的方式实现 。
Component接口:定义装饰物执行的公共操作
public interface IceCream { // 顶层接口
void AddTopping();
}
ConcreteComponent起始对象,在其基础上增加功能(装饰),将通用的方法放 到此对象中。
public class PlainIceCream implements IceCream {
@Override
public void AddTopping() {
System.out.println("Plain IceCream ready for some toppings!");
}
}
Decorator抽象类是所有装饰类的基类,里面包含的成员变量是上面那个
public abstract class ToppingDecorator implements IceCream {
protected IceCream input;
public ToppingDecorator(IceCream i) {
this.input = i;
}
@Override
public abstract void AddTopping();
}
继承Decorator的类是作为装饰的东西
public class CandyTopping extends ToppingDecorator {
public CandyTopping(IceCream i) {
super(i);
}
@Override
public void AddTopping() {
input.AddTopping();
System.out.println("Candy Topping added!");
}
}
调用方式如下(除了CandyTopping装饰,还写了PeanutTopping与NutsTopping。实现与CandyTopping类似):
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();
}
UML图:
Decorator在运行时编写功能
装饰器由多个协作对象组成
可以混搭多个装饰品
- Facade
一个Facade类,包含众多类的方法。用户不调用“众多类”,调用Facade类。UML图:
行为模式
如何交互和分配责任
- Strategy
针对特定任务存在多种算法,调用者需要根据上下文环境动 态的选择和切换。
实现:定义一个算法的 接口,每个算法用一个类来实现,客户端针对接口编写程序。
Strategy接口:
public interface PaymentStrategy {
public void pay(int amount);
}
Strategy子类只完成该方法即可
Context类:根据传进来的信息选择算法。返回对应算法需要返回的返回值
public class ShoppingCart {
public void pay(PaymentStrategy paymentMethod, int amount){
paymentMethod.pay(amount);
}
}
调用者:
ShoppingCart cart = new ShoppingCart();
int amount;
...
cart.pay(new PaypalStrategy(), amount); //PaypalStrategy()是继承自PaymentStrategy的方法
- Template method (模板方法)
不同的客户端具有相同的算法步骤 ,但是每个步骤的具体实现不同。
实现:在父类(抽象类)中定义通用逻辑和各步骤的抽 象方法声明 ,子类中进行各步骤的具体实现。UML图:
上面的图很清晰,例子不想举了。
- Iterator
问题:客户端需要以统 一的、与元素类型无关的方式访问容器中的所有元素 。需要一种面向迭代的策略模式 。
效果:隐藏了容器的内部 实现 ;用统一的接口 支持多种遍历策略
UML图:
- Aggregate interface :获取迭代器对象的接口
- ConcreteAggregate class : 实现迭代器对象的获取
通用接口(下面三个方法一般都要有):
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
获得迭代器的接口:
public interface Iterable<T> {
Iterator<T> iterator();
}
具体实现类完成上面那个接口,且包含一个完成通用接口Iterator的内部类:
public class Pair<E> implements Iterable<E> {
private class PairIterator implements Iterator<E> {
private boolean seenFirst = false, seenSecond = false;
@Override
public boolean hasNext() {
return !seenSecond;
}
@Override
public E next() {
if (!seenFirst) {
seenFirst = true;
return first;
}
if (!seenSecond) {
seenSecond = true;
return second;
}
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
private final E first, second;
public Pair(E f, E s) {
first = f;
second = s;
}
@Override
public Iterator<E> iterator() {
return new PairIterator();
}
}
通常情况下,上面两个接口由java.lang提供,不需要自己写。这时调用迭代器的代码为
Pair<String> pair = new Pair<String>("foo", "bar");
for (String s : pair) { … }
但上面两个接口如果自己写则不能这么使用,使用方式如下:
Iterator<String> iterator = pair.iterator();
while (iterator.hasNext()) {
...
iterator.next();
}
感受
在所有模式中,感觉这6种模式算比较好理解的。