白话设计模式

Posted by He Zongjiang on 2019-11-10

所谓的设计模式(Design Pattern)其实是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。

所以你可能完全没学过设计模式也能写出很好的代码,设计模式只是解决问题的一种思路,你完全可以有自己的思路。但是了解一些常见的设计模式,肯定是对代码开发有帮助或者有启发作用。

一、单例模式

简单点说,就是一个应用程序中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一般通过getInstance()的方法来获取它们的实例。getInstance()的返回值是同一个对象的引用,并不是一个新的实例。

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
// 懒汉式
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) instance = new Singleton();
return instance;
}
}

// 饿汉式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton () { }
public static Singleton getInstance() {
return instance;
}
}

// 枚举
// 这种方式是Effective Java作者Josh Bloch 提倡的方式,
// 它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
public enum Singleton {
INSTANCE;
public void whateverMethod() { }
}

// 双重校验锁
public class Singleton {
private volatile static Singleton singleton;
private Singleton() { }
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null)
singleton = new Singleton2();
}
}
return singleton;
}
}

二、装饰者模式

对已有的业务逻辑进一步的封装,使其增加额外的功能,如Java中的IO流就使用了装饰者模式,用户在使用的时候,可以任意组装,达到自己想要的效果。

举个栗子,我想吃三明治,首先我需要一根香肠,我喜欢吃奶油,在香肠上面加一点奶油,再放一点蔬菜,最后再用两片面包夹一下,很丰盛的一顿午饭,营养又健康。

首先,我们需要写一个Food类,让其他所有食物都来继承这个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Food {

private String food_name;

public Food() { }

public Food(String food_name) {
this.food_name = food_name;
}

public String make() {
return food_name;
}
}

然后我们写几个子类继承它:

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
// 面包类
public class Bread extends Food {

private Food basic_food;

public Bread(Food basic_food) {
this.basic_food = basic_food;
}

public String make() {
return basic_food.make() + "+面包";
}
}

// 奶油类
public class Cream extends Food {

private Food basic_food;

public Cream(Food basic_food) {
this.basic_food = basic_food;
}

public String make() {
return basic_food.make() + "+奶油";
}
}

// 蔬菜类
public class Vegetable extends Food {

private Food basic_food;

public Vegetable(Food basic_food) {
this.basic_food = basic_food;
}

public String make() {
return basic_food.make() + "+蔬菜";
}
}

这几个类都是差不多的,构造方法传入一个Food类型的参数,然后在make方法中加入一些自己的逻辑,如果你还是看不懂为什么这么写,看看Test类是怎么写的,一看你就明白了

1
2
3
4
5
6
public class Test {
public static void main(String[] args) {
Food food = new Bread(new Vegetable(new Cream(new Food("香肠"))));
System.out.println(food.make());
}
}

一层一层封装,我们从里往外看:最里面 new 了一个香肠,在香肠的外面我包裹了一层奶油,在奶油的外面我又加了一层蔬菜,最外面我放的是面包,是不是很形象?这个设计模式简直跟现实生活中一摸一样。

三、工厂模式

简单工厂模式:一个抽象的接口,多个抽象接口的实现类,一个工厂类,用来实例化抽象的接口。

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
// 抽象产品类
abstract class Car {
public void run();
public void stop();
}

// 具体实现类
class Benz implements Car {
public void run() {
System.out.println("Benz开始启动了……");
}

public void stop() {
System.out.println("Benz停车了……");
}
}

class Ford implements Car {
public void run() {
System.out.println("Ford开始启动了……");
}

public void stop() {
System.out.println("Ford停车了……");
}
}

// 工厂类
class Factory {
public static Car getCarInstance(String type) {
Car c = null;
if ("Benz".equals(type))
c = new Benz();
else if ("Ford".equals(type))
c = new Ford();
return c;
}
}

public class Test {
public static void main(String[] args) {
Car c = Factory.getCarInstance("Benz");
c.run();
c.stop();
}
}

四、代理模式(proxy)

代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

举个具体的例子,到了一定的年龄,我们就要结婚,结婚是一件很麻烦的事情,可能会找司仪来主持婚礼,显得热闹,婚庆公司打算怎么安排婚礼的节目,在婚礼完毕以后婚庆公司会做什么,我们一概不知。别担心,我们只要把钱给人家,人家会把事情给我们做好。所以,这里的婚庆公司相当于代理角色。

代码实现请看:

1
2
3
4
5
// 代理接口
public interface ProxyInterface {
// 需要代理的是结婚这件事,如果还有其他事情需要代理,也可以写
void marry();
}

我们看看婚庆公司的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class WeddingCompany implements ProxyInterface {

private ProxyInterface proxyInterface;

public WeddingCompany(ProxyInterface proxyInterface) {
this.proxyInterface = proxyInterface;
}

@Override
public void marry() {
System.out.println("我们是婚庆公司的");
System.out.println("我们在做结婚前的准备工作");
System.out.println("节目彩排...");
System.out.println("工作人员分工...");
System.out.println("可以开始结婚了");
proxyInterface.marry();
System.out.println("结婚完毕,我们需要做后续处理,你们可以回家了,其余的事情我们公司来做");
}
}

婚庆公司需要做的事情很多,我们再看看结婚家庭的代码:

1
2
3
4
5
6
public class NormalHome implements ProxyInterface{
@Override
public void marry() {
System.out.println("我们结婚啦~");
}
}

这个已经很明显了,结婚家庭只需要结婚,而婚庆公司这个代理要包揽一切准备工作,也就是说把许多要做的事情外包给其他人做,这就是代理模式。

来看看测试类代码:

1
2
3
4
5
6
public class Test {
public static void main(String[] args) {
ProxyInterface proxyInterface = new WeddingCompany(new NormalHome());
proxyInterface.marry();
}
}