0%

设计模式

创建型

单例

Intent
确保一个类只有一个实例,并提供该实例的全局访问点。

Class Diagram
使用一个私有构造函数、一个私有静态变量以及一个公有静态函数来实现。

私有构造函数保证了不能通过构造函数来创建对象实例,只能通过公有静态函数返回唯一的私有静态变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
public class Singleton {
/*
以下实现中,私有静态变量 uniqueInstance 被延迟实例化,这样做的好处是,如果没有用到该类,那么就不会实例化 uniqueInstance,从而节约资源。

这个实现在多线程环境下是不安全的,如果多个线程能够同时进入 if (uniqueInstance == null) ,并且此时 uniqueInstance 为 null,
那么会有多个线程执行 uniqueInstance = new Singleton(); 语句,这将导致实例化多次 uniqueInstance。
*/
private static Singleton uniqueInstance;
private Singleton(){}
public static Singleton getUniqueInstance(){
if (uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
/*
Ⅱ 饿汉式-线程安全
线程不安全问题主要是由于 uniqueInstance 被实例化多次,采取直接实例化 uniqueInstance 的方式就不会产生线程不安全问题。
但是直接实例化的方式也丢失了延迟实例化带来的节约资源的好处。
*/
private static Singleton uniqueInstance2 = new Singleton();
/*
Ⅲ 懒汉式-线程安全
只需要对 getUniqueInstance() 方法加锁,那么在一个时间点只能有一个线程能够进入该方法,从而避免了实例化多次 uniqueInstance。

但是当一个线程进入该方法之后,其它试图进入该方法的线程都必须等待,
即使 uniqueInstance 已经被实例化了。这会让线程阻塞时间过长,因此该方法有性能问题,不推荐使用。
*/
public static synchronized Singleton getUniqueInstance2(){
if (uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
/*
Ⅳ 双重校验锁-线程安全
uniqueInstance 只需要被实例化一次,之后就可以直接使用了。加锁操作只需要对实例化那部分的代码进行,
只有当 uniqueInstance 没有被实例化时,才需要进行加锁。

双重校验锁先判断 uniqueInstance 是否已经被实例化,如果没有被实例化,那么才对实例化语句进行加锁。
*/
public static Singleton getUniqueInstance3(){
if (uniqueInstance == null){
synchronized (Singleton.class){
if (uniqueInstance==null){
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
/*
考虑下面的实现,也就是只使用了一个 if 语句。在 uniqueInstance == null 的情况下,如果两个线程都执行了 if 语句,
那么两个线程都会进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 uniqueInstance = new Singleton();
这条语句,只是先后的问题,那么就会进行两次实例化。因此必须使用双重校验锁,也就是需要使用两个 if 语句:
第一个 if 语句用来避免 uniqueInstance 已经被实例化之后的加锁操作,而第二个 if 语句进行了加锁,
所以只能有一个线程进入,就不会出现 uniqueInstance == null 时两个线程同时进行实例化操作。
if (uniqueInstance == null) {
synchronized (Singleton.class) {
uniqueInstance = new Singleton();
}
}
*/
/*
Ⅴ 静态内部类实现
当 Singleton 类被加载时,静态内部类 SingletonHolder 没有被加载进内存。
只有当调用 getUniqueInstance() 方法从而触发 SingletonHolder.INSTANCE 时 SingletonHolder 才会被加载,
此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。

这种方式不仅具有延迟初始化的好处,而且由 JVM 提供了对线程安全的支持。
*/
private static class SingletonHolder{
private static final Singleton INSTANCE =new Singleton();
}
public static Singleton getUniqueInstance4(){
return SingletonHolder.INSTANCE;
}

}

简单工厂

Intent
在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口。

Class Diagram
简单工厂把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个具体子类来实例化。

这样做能把客户类和具体子类的实现解耦,客户类不再需要知道有哪些子类以及应当实例化哪个子类。客户类往往有多个,如果不使用简单工厂,那么所有的客户类都要知道所有子类的细节。而且一旦子类发生改变,例如增加子类,那么所有的客户类都要进行修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public interface Product {
}
public class ConcreteProduct implements Product {
}
public class ConcreteProduct1 implements Product {
}
public class ConcreteProduct2 implements Product {
}
public class Client {

public static void main(String[] args) {
int type = 1;
Product product;
if (type == 1) {
product = new ConcreteProduct1();
} else if (type == 2) {
product = new ConcreteProduct2();
} else {
product = new ConcreteProduct();
}
// do something with the product
}
}
/**
实现
*/
public class SimpleFactory {

public Product createProduct(int type) {
if (type == 1) {
return new ConcreteProduct1();
} else if (type == 2) {
return new ConcreteProduct2();
}
return new ConcreteProduct();
}
}

工厂方法

Intent
定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。

Class Diagram
在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。

下图中,Factory 有一个 doSomething() 方法,这个方法需要用到一个产品对象,
这个产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public abstract class Factory {
abstract public Product factoryMethod();
public void doSomething() {
Product product = factoryMethod();
// do something with the product
}
}
public class ConcreteFactory extends Factory {
public Product factoryMethod() {
return new ConcreteProduct();
}
}
public class ConcreteFactory1 extends Factory {
public Product factoryMethod() {
return new ConcreteProduct1();
}
}
public class ConcreteFactory2 extends Factory {
public Product factoryMethod() {
return new ConcreteProduct2();
}
}

抽象工厂

Intent
提供一个接口,用于创建 相关的对象家族 。

Class Diagram
抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂方法模式只是用于创建一个对象,这和抽象工厂模式有很大不同。

抽象工厂模式用到了工厂方法模式来创建单一对象,AbstractFactory 中的 createProductA() 和 createProductB() 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂方法模式的定义。

至于创建对象的家族这一概念是在 Client 体现,Client 要通过 AbstractFactory 同时调用两个方法来创建出两个对象,在这里这两个对象就有很大的相关性,Client 需要同时创建出这两个对象。

从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory,而工厂方法模式使用了继承。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class AbstractProductA {
}
public class AbstractProductB {
}
public class ProductA1 extends AbstractProductA {
}
public class ProductA2 extends AbstractProductA {
}
public class ProductB1 extends AbstractProductB {
}
public class ProductB2 extends AbstractProductB {
}
public abstract class AbstractFactory {
abstract AbstractProductA createProductA();
abstract AbstractProductB createProductB();
}
public class ConcreteFactory1 extends AbstractFactory {
AbstractProductA createProductA() {
return new ProductA1();
}

AbstractProductB createProductB() {
return new ProductB1();
}
}
public class ConcreteFactory2 extends AbstractFactory {
AbstractProductA createProductA() {
return new ProductA2();
}

AbstractProductB createProductB() {
return new ProductB2();
}
}
public class Client {
public static void main(String[] args) {
AbstractFactory abstractFactory = new ConcreteFactory1();
AbstractProductA productA = abstractFactory.createProductA();
AbstractProductB productB = abstractFactory.createProductB();
// do something with productA and productB
}
}

生成器

Intent
封装一个对象的构造过程,并允许按步骤构造。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* 设计模式的生成器
* 模仿StringBuilder
* @Author 87312
*/
public class AbstractStringBuilder {

protected char[] value;

protected int count;
//构造方法
public AbstractStringBuilder(int capacity){
count=0;
value = new char[capacity];
}

public AbstractStringBuilder append(char c){
ensureCapacityInternal(count+1);
value[count++] = c;
return this;
}

private void ensureCapacityInternal(int minimumCapacity){
if (minimumCapacity - value.length>0){
expandCapacity(minimumCapacity);
}
}

void expandCapacity(int minimumCapacity){
int newCapacity = value.length*2+2;
if (newCapacity - minimumCapacity < 0){
newCapacity = minimumCapacity;
}
if (newCapacity < 0 ){
if (minimumCapacity<0) throw new OutOfMemoryError();// overflow
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value,newCapacity);
}
}

原型模式

Intent
使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象。
一般原型模式写的是深克隆,即克隆出一个完全一样和本地不是一个地址的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class Prototype implements Cloneable{
interface Pro{
Object myClone() throws CloneNotSupportedException;
}
public static class Plane implements Cloneable, Serializable {
private String name; //附件名

private Date data;

public Date getData() {
return data;
}

public void setData(Date data) {
this.data = data;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
public void download() {
System.out.println("下载附件"+name);
}
@Override
public Object clone() throws CloneNotSupportedException{
Object object = super.clone();
// 实现深度克隆(deep clone)
Plane plane = (Plane)object;
plane.data = (Date) this.data.clone();
return object;
}
}
@Test
public void ll() throws CloneNotSupportedException {
Plane plane = new Plane();
plane.setData(new Date());
System.out.println(plane);
System.out.println(new Plane());
System.out.println(plane.clone());
}
}

行为型

责任链

Intent
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。

Class Diagram
Handler:定义处理请求的接口,并且实现后继链(successor)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public class ChainOfResponsibility {
public class Request {

private RequestType type;
private String name;


public Request(RequestType type, String name) {
this.type = type;
this.name = name;
}


public RequestType getType() {
return type;
}


public String getName() {
return name;
}
}
public enum RequestType {
TYPE1, TYPE2
}
abstract class Handler {

protected Handler successor;


public Handler(Handler successor) {
this.successor = successor;
}


protected abstract void handleRequest(Request request);
}
public class ConcreteHandler1 extends Handler {

public ConcreteHandler1(Handler successor) {
super(successor);
}


@Override
protected void handleRequest(Request request) {
if (request.getType() == RequestType.TYPE1) {
System.out.println(request.getName() + " is handle by ConcreteHandler1");
return;
}
if (successor != null) {
successor.handleRequest(request);
}
}
}
public class ConcreteHandler2 extends Handler {

public ConcreteHandler2(Handler successor) {
super(successor);
}


@Override
protected void handleRequest(Request request) {
if (request.getType() == RequestType.TYPE2) {
System.out.println(request.getName() + " is handle by ConcreteHandler2");
return;
}
if (successor != null) {
successor.handleRequest(request);
}
}
}
@Test
public void test(){
Handler handler1 = new ConcreteHandler1(null);
Handler handler2 = new ConcreteHandler2(handler1);

Request request1 = new Request(RequestType.TYPE1, "request1");
handler2.handleRequest(request1);

Request request2 = new Request(RequestType.TYPE2, "request2");
handler2.handleRequest(request2);

}
}

命令

Intent
将命令封装成对象中,具有以下作用:

使用命令来参数化其它对象
将命令放入队列中进行排队
将命令的操作记录到日志中
支持可撤销的操作
Class Diagram
Command:命令
Receiver:命令接收者,也就是命令真正的执行者
Invoker:通过它来调用命令
Client:可以设置命令与命令的接收者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

/**
* @Author 87312
*/
public class CommandModel {
interface Command {
void execute();
}
public class Light {

public void on() {
System.out.println("Light is on!");
}

public void off() {
System.out.println("Light is off!");
}
}
public class LightOnCommand implements Command {
Light light;

public LightOnCommand(Light light) {
this.light = light;
}

@Override
public void execute() {
light.on();
}
}
public class LightOffCommand implements Command {
Light light;

public LightOffCommand(Light light) {
this.light = light;
}

@Override
public void execute() {
light.off();
}
}
public class Invoker{
private Command[] onCommands;
private Command[] offCommands;
private final int slotNum = 7;
public Invoker() {
this.onCommands = new Command[slotNum];
this.offCommands = new Command[slotNum];
}
public void setOnCommand(Command command, int slot) {
onCommands[slot] = command;
}

public void setOffCommand(Command command, int slot) {
offCommands[slot] = command;
}

public void onButtonWasPushed(int slot) {
onCommands[slot].execute();
}

public void offButtonWasPushed(int slot) {
offCommands[slot].execute();
}
}
@Test
public void test(){
Invoker invoker = new Invoker();
Light light = new Light();
Command lightOnCommand = new LightOnCommand(light);
Command lightOffCommand = new LightOffCommand(light);
invoker.setOnCommand(lightOnCommand, 1);
invoker.setOffCommand(lightOffCommand, 1);
invoker.onButtonWasPushed(1);
invoker.offButtonWasPushed(1);
}
}

解释器

提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。

主要解决:对于一些固定文法构建一个解释句子的解释器。

Implementation
以下是一个规则检验器实现,具有 and 和 or 规则,通过规则可以构建一颗解析树,用来检验一个文本是否满足解析树定义的规则。

例如一颗解析树为 D And (A Or (B C)),文本 “D A” 满足该解析树定义的规则。

这里的 Context 指的是 String。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/**为语言创建解释器,通常由语言的语法和语法分析来定义。
* @Author 87312
*/
public class Interpreter {
public abstract class Expression {
public abstract boolean interpret(String str);
}
public class TerminalExpression extends Expression {

private String literal = null;

public TerminalExpression(String str) {
literal = str;
}

public boolean interpret(String str) {
StringTokenizer st = new StringTokenizer(str);
while (st.hasMoreTokens()) {
String test = st.nextToken();
if (test.equals(literal)) {
System.out.println("执行interpret");
return true;
}
}
System.out.println("执行interpret");
return false;
}
}
public class AndExpression extends Expression {

private Expression expression1 = null;
private Expression expression2 = null;

public AndExpression(Expression expression1, Expression expression2) {
this.expression1 = expression1;
this.expression2 = expression2;
}

public boolean interpret(String str) {
System.out.println("执行interpret");
return expression1.interpret(str) && expression2.interpret(str);
}
}
public class OrExpression extends Expression {
private Expression expression1 = null;
private Expression expression2 = null;

public OrExpression(Expression expression1, Expression expression2) {
this.expression1 = expression1;
this.expression2 = expression2;
}

public boolean interpret(String str) {
System.out.println("执行interpret");
return expression1.interpret(str) || expression2.interpret(str);
}
}
/**
* 构建解析树
*/
public Expression buildInterpreterTree() {
// Literal
Expression terminal1 = new TerminalExpression("A");
Expression terminal2 = new TerminalExpression("B");
Expression terminal3 = new TerminalExpression("C");
Expression terminal4 = new TerminalExpression("D");
// B C
Expression alternation1 = new OrExpression(terminal2, terminal3);
// A Or (B C)
Expression alternation2 = new OrExpression(terminal1, alternation1);
// D And (A Or (B C))
return new AndExpression(terminal4, alternation2);
}
@Test
public void test(){
Expression define = buildInterpreterTree();
String context1 = "D A";
String context2 = "A B";
System.out.println(define.interpret(context1));
System.out.println(define.interpret(context2));
}
}

迭代器

Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。迭代器模式属于行为型模式。

主要解决:不同的方式来遍历整个整合对象。
分为三步:

  • 1、创建接口:
  • 2、创建实现了接口的实体类。
  • 3、使用.来获取迭代器,并打印名字。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    /**迭代器 提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。
    * @Author 87312
    */
    public class Iterator {

    public interface Aggregate {
    Iterator2 createIterator();
    }
    public class ConcreteAggregate implements Aggregate {

    private Integer[] items;

    public ConcreteAggregate() {
    items = new Integer[10];
    for (int i = 0; i < items.length; i++) {
    items[i] = i;
    }
    }

    @Override
    public Iterator2 createIterator() {
    return new ConcreteIterator<Integer>(items);
    }
    }
    public interface Iterator2<Item> {

    Item next();

    boolean hasNext();
    }
    public class ConcreteIterator<Item> implements Iterator2 {

    private Item[] items;
    private int position = 0;

    public ConcreteIterator(Item[] items) {
    this.items = items;
    }

    @Override
    public Object next() {
    return items[position++];
    }

    @Override
    public boolean hasNext() {
    return position < items.length;
    }
    }
    @Test
    public void test(){
    ConcreteAggregate aggregate = new ConcreteAggregate();
    Iterator2 iterator = aggregate.createIterator();
    while (iterator.hasNext()){
    System.out.println(iterator.next());
    }
    }
    }

    中介者

    备忘录

    观察者

    状态

    策略

    模板方法

    访问者

    空对象

    结构型

    适配器

    桥接

    组合

    装饰

    外观

    享元

    代理