4.3 面向复用的设计模式
一. 模式
- 创建模式
- 结构模式
- 适配器模式
- 装饰模式
- 门面/外观模式
- 行为模式
- 策略模式
- 模板模式
- 迭代器模式
1. 结构型模式
1.1 适配器模式
解决接口不匹配的情况。也可以说是将某个类/接口转换为 client
期望的其他形式。
- 通过增加一个接口,将已存在的子类封装起来,
client
面向接口编程,从而隐藏了具体子类。
如下是参数不匹配的例子(属接口不匹配),通过适配器(中转的类,将不适合的接口变得适合):
源程序:
class LegacyRectangle {
void display(int x1, int y1, 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 LegacyRectangle {
void display(int x1, int y1, int w, int h) {...}
}
class Client {
Shape shape = new Rectangle();
public display() {
shape.display(x1, y1, x2, y2);
}
}
1.2 装饰模式
为对象增加不同侧面的特性。对每一个特性构造子类,通过委托机制增加到对象上。
interface Stack {
void push(Item e);
Item pop();
}
public class ArrayStack implements Stack {
... //rep
public ArrayStack() {...}
public void push(Item e) {
...
}
public Item pop() {
...
}
...
}
public abstract class StackDecorator implements Stack {
protected final Stack stack;
public StackDecorator(Stack stack)
this.stack = stack;
}
public void push(Item e) {
stack.push(e);
}
public Item pop() {
return stack.pop();
}
...
}
public class UndoStack extends StackDecorator implements Stack {
private final UndoLog log = new UndoLog();
public UndoStack (Stack stack) {
super(stack);
}
public void push(Item e) {
log.append(UndoLog.PUSH, e);
super.push(e);
}
public void undo() {
//implement decorator behaviors on stack
}
...
}
层层包装形式使用:
Stack s = new ArrayStack();//普通
Stack t = new UndoStack (new ArrayStack());//undo stack
Stack t = new SecureStack(new SynchronizedStack(new UndoStack(s));//secure synchronized undo stack
层层包装有所限制,无法使用包装内部的方法,只能使用显式(接口)的方法。
Collections
提供的包装类提供的是引用,一个指向原 List
或 Set
或 Map
的对象。
1.3 外观/门面模式
客户端需要通过一个简化的接口来访问复杂系统内的功能。
提供一个统一的接口来取代一系列小接口调用,相当于对复杂系统做了一个封装,简化客户端使用。
public class MySqlHelper {
public static Connection getMySqlDBConnection() {...}
public void generateMySqlPDFReport(String tableName, Connection con) {...}
public void generateMySqlHTMLReport(String tableName, Connection con) {...}
}
public class OracleHelper {
public static Connection getOracleDBConnection() {...}
public void generateOraclePDFReport(String tableName, Connection con) {...}
public void generateOracleHTMLReport(String tableName, Connection con) {...}
}
public class HelperFacade {
public static void generateReport(DBTypes dbType, ReportTypes reportType, String tableName){
Connection con = null;
switch (dbType){
case MYSQL:
con = MySqlHelper.getMySqlDBConnection();
MySqlHelper mySqlHelper = new MySqlHelper();
switch(reportType){
case HTML:
mySqlHelper.generateMySqlHTMLReport(tableName, con);
break;
case PDF:
mySqlHelper.generateMySqlPDFReport(tableName, con);
break;
}
break;
case ORACLE: ...
}
public static enum DBTypes { MYSQL,ORACLE;}
public static enum ReportTypes { HTML,PDF;}
}
2. 行为型模式
2.1 策略模式
有多种不同的算法来实现同一个任务,但需要 client
根据需要动态切换算法,而不是写死在代码里。
为不同的实现算法构造抽象接口,利用 delegation
,运行时动态传入 client
倾向的算法类实例。
2.2 模板模式
做事情的步骤一样,但具体方法不同。共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现。
方法是:使用继承和重写实现模板模式。(白盒框架)
注:final
可以限制方法,不让它被重写。
public abstract class OrderProcessTemplate {
public boolean isGift;
public abstract void doSelect();
public abstract void doPayment();
public final void giftWrap() {
System.out.println("Gift wrap done");
}
public abstract void doDelivery();
public final void processOrder() {
doSelect();
doPayment();
if (isGift)
giftWrap();
doDelivery();
}
}
2.3 迭代器模式
客户端希望遍历被放入容器/集合类的一组 ADT
对象,无需关心容器的具体类型
- 也就是说,不管对象被放进哪里,都应该提供同样的遍历方式
集合端继承Iterable
接口,使实现该接口的集合对象是可迭代遍历的
public interface Iterable<T> {
...
Iterator<T> iterator();//返回指向当前集合的迭代器
}
Iterator
接口:迭代器
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
迭代器模式:让自己的集合类实现 Iterable
接口,并实现自己的独特 Iterator
迭代器 (hasNext
, next
, remove
),允许客户端利用这个迭代器进行显式或隐式的迭代遍历:
for (E e : collection) {...}
Iterator<E> iter = collection.iterator();
while(iter.hasNext()) {...}
迭代器类是 immutable
类型。使得 remove
操作元素时,只能使用迭代器的 remove
操作。
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 PairIterator 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; return second; }
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}
Pair<String> pair = new Pair<String>("foo", "bar");
for (String s : pair) { … }