设计模式

[toc]

零、资料

一、创建型

1、单例模式

单例模式(Singleton)是一种非常简单且容易理解的设计模式。

顾名思义,单例即单一的实例,确切地讲就是指在某个系统中只存在一个实例,同时提供集中、统一的访问接口,以使系统行为保持协调一致。

1.1、饿汉式

注意事项:

  • private单例类的无参构造器。
  • 单例类的内部定义一个单例类类型的静态常量作为成员变量。
  • 提供一个public的静态获取单例的方法。
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
public class HungrySingletonTest {

public static void main(String[] args) {

HungrySingleton instance1 = HungrySingleton.getInstance();
HungrySingleton instance2 = HungrySingleton.getInstance();
System.out.println(instance1==instance2); // true

}
}

// ----------------------------------

class HungrySingleton {
// (2)
private static final HungrySingleton singleton = new HungrySingleton();

// (1)
private HungrySingleton() {}

// (3)
public static HungrySingleton getInstance(){
return singleton;
}

}

1.2、懒汉式

注意事项:

  • private无参构造器
  • 单例类的内部定义一个单例类类型的静态成员变量,并且使用volatile关键字来修饰,保证多线程时给成员变量的同步性、唯一性
  • 提供一个public的静态获取单例的方法。该方法内需要先判断实例是否为空,若不为空,则直接返回;若为空,则对该实例的Class对象加锁,加锁后如果仍然为空,则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
public class LazySingletonTest {

public static void main(String[] args) {
LazySingleton instance1 = LazySingleton.getInstance();
LazySingleton instance2 = LazySingleton.getInstance();
System.out.println(instance1 == instance2); // true
}
}

class LazySingleton{
// (2)
private volatile static LazySingleton singleton;

// (1)
private LazySingleton() {}

// (3)
public static LazySingleton getInstance(){
// 双检锁
if (singleton==null){
synchronized (LazySingleton.class){
if (singleton==null){
singleton = new LazySingleton();
}
}
}

return singleton;
}
}

2、工厂方法模式

一个工厂,生产多种产品。

步骤:

  • 产品接口
  • 产品接口的实现类
  • 工厂

(1)产品接口-Car:

1
2
3
public interface Car {
public void driver();
}

(2-1)产品实现类-BMWCar:

1
2
3
4
5
6
public class BMWCar implements Car{
@Override
public void driver() {
System.out.println("BMWCar。。。。驾驶");
}
}

(2-2)产品实现类-AudiCar:

1
2
3
4
5
6
public class AudiCar implements Car{
@Override
public void driver() {
System.out.println("AudiCar。。。。驾驶");
}
}

(3)工厂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class CarFactory2 {
// 根据传入的品牌名,创建不同的产品
public static Car produceCar(String brand){

Car car = null;

switch(brand){
case "bmw":{
car = new BMWCar();
break;
}
case "audi":{
car = new AudiCar();
break;
}
}

return car;
}

}


(4)调用:

1
2
3
4
5
6
7
8
9
10
public class Test {
public static void main(String[] args) {

Car car1 = CarFactory2.produceCar("bmw");
Car car2 = CarFactory2.produceCar("audi");
car1.driver();
car2.driver();
}
}

静态工厂方法:

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
public class CarFactory2 {
// 根据传入的品牌名,创建不同的产品
public static Car produceCar(String brand){

Car car = null;

switch(brand){
case "bmw":{
car = new BMWCar();
break;
}
case "audi":{
car = new AudiCar();
break;
}
default:{
car = new BydCar();
break;
}
}

return car;
}

}


3、抽象工厂模式

多个工厂,生产多种产品。

四个主要的涉及的代码:

  • 工厂接口
  • 工厂接口的实现类
  • 产品接口
  • 产品接口的实现类

步骤:

  • 产品接口,定义产品接口的抽象方法
  • 产品接口的实现类,实现产品接口的抽象方法
  • 工厂接口,定义工厂接口(用于生产产品)的抽象方法
  • 工厂接口的实现类,实现工厂(用于生产产品)的抽象方法
  • 工厂接口,new 一个实现类,赋值给一个static工厂类型的成员变量
  • 工厂接口,编写一个static提供工厂实现类的方法。

(1)产品接口:

1
2
3
public interface Car {
public void driver();
}

(2)产品实现类:

1
2
3
4
5
6
public class BMWCar implements Car{
@Override
public void driver() {
System.out.println("BMWCar。。。。驾驶");
}
}

(3)工厂接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//先工厂接口,再实现类,再继续工厂接口
public interface CarFactory {

// (1)
public Car produceCar();

// (3)
public static CarFactory factory = new CarFactoryImpl();

// (4)
public static CarFactory getFactory(){
return factory;
}

}

(4)工厂实现类:

1
2
3
4
5
6
7
public class CarFactoryImpl implements CarFactory{
// (2)
@Override
public Car produceCar() {
return new BMWCar();
}
}

4、原型模式

原型模式,即Prototype,是指创建新对象的时候,根据现有的一个类来创建。

步骤:

  • 实现Cloneable接口,重写Object类的 clone() 方法。
  • 复制数据,返回 对象。
  • 获取并强转新对象。

初始版本:(缺点:获取新的对象后,需要强转数据类型)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Student implements Cloneable {
private int id;
private String name;
private int score;

// 复制新对象并返回:
public Object clone() {
Student std = new Student();
std.id = this.id;
std.name = this.name;
std.score = this.score;
return std;
}
}

优化版本:(直接定义一个复制方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Student {
private int id;
private String name;
private int score;

public Student copy() {
Student std = new Student();
std.id = this.id;
std.name = this.name;
std.score = this.score;
return std;
}
}

5、生成器模式

生成器模式(Builder)是使用多个“小型”工厂来最终创建出一个完整对象。

1
2
3
4
5
6
7
8
// 此处案例使用了链式编程,链式编程就是函数的返回值是调用方法的那个对象,因此可以一直调用方法

String url = URLBuilder.builder() // 创建Builder
.setDomain("www.liaoxuefeng.com") // 设置domain
.setScheme("https") // 设置scheme
.setPath("/") // 设置路径
.setQuery(Map.of("a", "123", "q", "K&R")) // 设置query
.build(); // 完成build

二、结构型

1、适配器模式

适配器 - 廖雪峰

适配器模式是Adapter,也称Wrapper,是指如果一个接口待传入的对象是A接口,但是却需要B接口,这种情况下的接口转换。

List<T> Arrays.asList(T[])方法就相当于一个转换器,它可以把数组转换为List

Adapter模式可以将一个A接口转换为B接口,使得新的对象符合B接口规范。

编写Adapter实际上就是编写一个实现了B接口,并且内部持有A接口的类:

1
2
3
4
5
6
7
8
9
public BAdapter implements B {
private A a;
public BAdapter(A a) {
this.a = a;
}
public void b() {
a.a();
}
}

Adapter内部将B接口的调用“转换”为对A接口的调用。

只有A、B接口均为抽象接口时,才能非常简单地实现Adapter模式。

2、桥接模式

桥接模式就是为了避免直接继承带来的子类数量大量增加。

桥接模式实现比较复杂,实际应用也非常少,但它提供的设计思想值得借鉴,即不要过度使用继承,而是优先拆分某些部件,使用组合的方式来扩展功能。

五个部分:

  • 一个抽象类
  • 一个接口
  • 抽象类的修正类(作用:与接口产生关联)
  • 接口的实现类
  • 修正类的实现类

例子:

Enigne 接口

1
2
3
public interface Engine {
void start();
}

Car 抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package car;

import engine.Engine;

public abstract class Car{
protected Engine engine;

public Car(Engine engine) {
this.engine = engine;
}

public abstract void drive();

}

RefinedCar 抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package car;

import engine.Engine;

public abstract class RefinedCar extends Car{

public RefinedCar(Engine engine) {
super(engine);
}

public abstract String getBrand();

@Override
public void drive() {
this.engine.start();
System.out.println("Drive " + getBrand() + " car...");
}
}

AudiCar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package car;

import engine.Engine;

public class AudiCar extends RefinedCar{

public AudiCar(Engine engine) {
super(engine);
}

@Override
public String getBrand() {
return "audi";
}
}

HybridEngine

1
2
3
4
5
6
7
8
package engine;

public class HybridEngine implements Engine{
@Override
public void start() {
System.out.println("Start Hybrid Engine...");
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
import car.AudiCar;
import car.RefinedCar;
import engine.HybridEngine;

public class Test {
public static void main(String[] args) {
RefinedCar audiCar = new AudiCar(new HybridEngine());
audiCar.drive();
}
}

三、行为型