单例模式
1. 饿汉式
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
|
public class SingletonDemo1 { public static void main(String[] args) { Singleton instance1 = Singleton.getInstance(); Singleton instance2 = Singleton.getInstance(); System.out.println(instance1 == instance2); }
}
class Singleton { private Singleton() {
}
private final static Singleton instance = new Singleton();
public static Singleton getInstance() { return instance; }
}
private static Singleton2 instance;
static { instance = new Singleton2(); }
|
2. 懒汉式
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
|
public class SingletonDemo3 { public static void main(String[] args) { Singleton5 instance1 = Singleton5.getInstance(); Singleton5 instance2 = Singleton5.getInstance(); System.out.println(instance1 == instance2); } }
class Singleton3 { private static Singleton3 instance;
private Singleton3() { }
public static Singleton3 getInstance() { if (instance == null) { instance = new Singleton3(); } return instance; } }
|
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
|
class Singleton5 {
private static volatile Singleton5 instance;
private Singleton5() { }
public static Singleton5 getInstance() { if (instance == null) { synchronized (Singleton5.class) { if (instance == null) { instance = new Singleton5(); } } } return instance; } }
|
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
|
public class SingletonDemo5 { public static void main(String[] args) { Singleton5 instance1 = Singleton5.getInstance(); Singleton5 instance2 = Singleton5.getInstance(); System.out.println("静态内部类,推荐使用:" + (instance1 == instance2)); } }
class Singleton5 { private static Singleton5 instance;
private Singleton5() { }
private static class SingletonInstance { private static final Singleton5 INSTANCE = new Singleton5(); }
public static Singleton5 getInstance() { return SingletonInstance.INSTANCE; } }
|
4. 枚举
- Effective Java 作者 Josh Bloch 提倡的方式
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
|
public class SingletonDemo {
public static void main(String[] args) { Singleton instance = Singleton.INSTANCE; Singleton instance2 = Singleton.INSTANCE; System.out.println(instance == instance2);
System.out.println(instance.hashCode()); System.out.println(instance2.hashCode());
instance.sayOK(); } }
enum Singleton {
INSTANCE; public void sayOK() { System.out.println("ok~"); } }
|
5.单例模式在 JDK 应用的源码分析
原型模式
1.基本介绍
原型模式(Prototype 模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象
原型模式是一种 创建型设计模式,允许一个 对象再创建另外一个可定制的对象,无需知道如何创建的细节
工作原理是: 通过将一个原型对象传给那个要发动创建的对象,这个 要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即 原型对象.clone()
2.传统方式解决克隆羊问题
克隆羊问题:
现在有一只羊 tom,姓名为: tom, 年龄为:1,颜色为:白色,请编写程序创建和 tom 羊 属性完全相同的 10只羊。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public class Client {
public static void main(String[] args) {
Sheep sheep = new Sheep("tom", 1, "白色");
Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor()); Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor()); Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
Sheep sheep5 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor()); }
}
|
传统的方式的优缺点
- 优点是比较好理解,简单易操作。
- 在创建新的对象时,总是需要 重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低
- 总是需要重新初始化对象,而不是动态地获得对象运行时的状态, 不够灵活
改进的思路分析:
- Object 类提供了一个 clone()方法,该方法可以将一个 Java 对象复制一份,
- 实现 clone 的 Java 类必须要实现一个 接口 Cloneable,该接口表示 该类能够复制且具有复制的能力 =>原型模式
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 59 60 61 62 63 64 65
|
public class Sheep implements Cloneable { private String name; private int age; private String color; private String address = "蒙古羊"; public Sheep friend;
public Sheep(String name, int age, String color) { this.name = name; this.age = age; this.color = color; }
@Override public String toString() { return "Sheep{" + "name='" + name + '\'' + ", age=" + age + ", color='" + color + '\'' + ", address='" + address + '\'' + ", friend=" + friend + '}'; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getColor() { return color; }
public void setColor(String color) { this.color = color; }
@Override protected Object clone() { Sheep sheep = null; try { sheep = (Sheep) super.clone(); } catch (Exception e) { e.getStackTrace(); } return sheep; } }
|
1 2 3 4 5 6
| Sheep sheep = new Sheep("tom", 1, "白色"); sheep.friend = new Sheep("jack", 2, "黑色"); Sheep sheep2 = (Sheep) sheep.clone();
System.out.println("sheep2 =" + sheep2 + "sheep2.friend=");
|
4.原型模式在 Spring 框架中源码分析
Spring 中原型 bean 的创建,就是原型模式的应用(后面代码debug)
5.深入讨论-浅拷贝和深拷贝
浅拷贝的介绍
- 对于数据类型是 基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该 属性值复制一份给新的对象。
- 对于数据类型是 引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行 引用传递,也就是只是将该 成员变量的引用值(内存地址)复制一份给新的对象。因为 实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值
- 前面我们克隆羊就是浅拷贝
- 浅拷贝是使用 默认的 clone()方法来实现 sheep = (Sheep) super.clone();
深拷贝基本介绍
- 复制对象的所有基本数据类型的成员变量值
- 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝
- 深拷贝实现方式:1.重写 clone 方法来实现深拷贝 2.通过对象序列化实现深拷贝(推荐)
6.深拷贝应用实例
7.原型模式的注意事项和细节
- 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
- 不用重新初始化对象,而是动态地获得对象运行时的状态
- 如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
- 在实现深克隆的时候可能需要比较复杂的代码
- 缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了 ocp 原则.
建造者模式
1 2 3 4
| 前言(需要建房子): 这一过程为打桩、砌墙、封顶房子有各种各样的, 比如普通房,高楼,别墅,各种房子的过程虽然一样,但是要求不要相同的. 请编写程序,完成需求.
|
1.传统模式解决盖房需求
思路分析

代码演示
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
| public abstract class AbstractHouse {
public abstract void buildBasic(); public abstract void buildWalls(); public abstract void roofed();
public void build() { buildBasic(); buildWalls(); roofed(); }
}
public class CommonHouse extends AbstractHouse {
@Override public void buildBasic() { System.out.println(" 普通房子打地基 "); }
@Override public void buildWalls() { System.out.println(" 普通房子砌墙 "); }
@Override public void roofed() { System.out.println(" 普通房子封顶 "); }
}
|
2.基本介绍
1 2 3 4 5 6
| 建造者模式(Builder Pattern) 又叫生成器模式,是一种对象构建模式。 它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法 可以构造出不同表现(属性)的对象。
建造者模式 是一步一步创建一个复杂的对象,它允许用户只通过 指定复杂对象的类型和内容就可以构建它们, 用户不需要知道内部的具体构建细节。
|
3.四个角色
Product(产品角色): 一个具体的产品对象。
Builder(抽象建造者): 创建一个 Product 对象的各个部件指定的 接口/抽象类。
ConcreteBuilder(具体建造者): 实现接口,构建和装配各个部件。
Director(指挥者): 构建一个使用 Builder 接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。
4.应用实例

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 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
| public class Client {
public static void main(String[] args) { CommonHouse commonHouse = new CommonHouse();
HouseDirector houseDirector = new HouseDirector(commonHouse);
House house = houseDirector.constructHouse();
HighBuilding highBuilding = new HighBuilding(); } }
=====================================================
public class CommonHouse extends HouseBuilder {
@Override public void buildBasic() { System.out.println(" 普通房子打地基 5 米 "); }
@Override public void buildWalls() { System.out.println(" 普通房子砌墙 10cm "); }
@Override public void roofed() { System.out.println(" 普通房子屋顶 "); } }
==================================================
public class HighBuilding extends HouseBuilder {
@Override public void buildBasic() { System.out.println(" 高楼的打地基 100 米 "); }
@Override public void buildWalls() {
}
@Override public void roofed() { System.out.println(" 高楼的透明屋顶 "); }
}
==================================================
public class House {
private String baise; private String wall; private String roofed; public String getBaise() { return baise; } public void setBaise(String baise) { this.baise = baise; } public String getWall() { return wall; } public void setWall(String wall) { this.wall = wall; } public String getRoofed() { return roofed; } public void setRoofed(String roofed) { this.roofed = roofed; }
}
==================================================
public abstract class HouseBuilder {
protected House house = new House();
public abstract void buildBasic(); public abstract void buildWalls(); public abstract void roofed();
public House buildHouse() { return house; }
}
==================================================
public class HouseDirector {
HouseBuilder houseBuilder = null;
public HouseDirector(HouseBuilder houseBuilder) { this.houseBuilder = houseBuilder; }
public void setHouseBuilder(HouseBuilder houseBuilder) { this.houseBuilder = houseBuilder; }
public House constructHouse() { houseBuilder.buildBasic(); houseBuilder.buildWalls(); houseBuilder.roofed(); return houseBuilder.buildHouse(); }
}
|
适配器模式(Adapter Pattern)
1.基本介绍
2.工作原理
- 将一个类的接口转换成另一种接口.让原本接口不兼容的类可以兼容
- 从用户的角度看不到被适配者,是 解耦的
- 用户调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法
类适配器模式
基本介绍:Adapter 类,通过继承被适配者 类,实现目标类接口,完成 被适配者 到 目标 的适配。
代码实现
首先有一个已存在的将被适配的类
1 2 3 4 5
| public class Adaptee { public void adapteeRequest() { System.out.println("被适配者的方法"); } }
|
定义一个目标类接口
1 2 3
| public interface Target { void request(); }
|
如果通过一个适配器类,实现 Target 接口,同时 继承了 Adaptee 类,然后在实现的 request() 方法中调用父类的 adaptee 中 adapteeRequest() 即可实现
1 2 3 4 5 6 7
| public class Adapter extends Adaptee implements Target{ @Override public void request() { System.out.println("Target目标方法"); super.adapteeRequest(); } }
|
测试
1 2 3 4 5 6 7 8
| public class Test { public static void main(String[] args) { Target adapterTarget = new Adapter(); adapterTarget.request(); } }
|
对象适配器模式
基本介绍:对象适配器与类适配器不同之处在于,类适配器通过继承来完成适配,对象适配器则是通过关联来完成,这里稍微修改一下 Adapter 类即可将转变为对象适配器
修改 Adapter 适配器类 即可
1 2 3 4 5 6 7 8 9 10 11
| public class Adapter implements Target{
private Adaptee adaptee = new Adaptee();
@Override public void request() { System.out.println("Target目标方法"); adaptee.adapteeRequest(); } }
|
接口适配器模式
基本介绍:适配器模式(Default Adapter Pattern)或缺省适配器模式,适用于一个接口不想使用其所有的方法的情况
核心思路:当 不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并 为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可 有选择地覆盖父类的某些方法来实现需求
提供接口
1 2 3 4 5 6
| public interface InterfaceProvide { void run1(); void run2(); void run3(); void run4(); }
|
实现接口,默认实现空方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class AbsAdapter implements InterfaceProvide{ @Override public void run1() { }
@Override public void run2() {
}
@Override public void run3() {
}
@Override public void run4() {
} }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Test {
public static void main(String[] args) { AbsAdapter absAdapter = new AbsAdapter() { @Override public void run1() { System.out.println("使用了 run1 的方法"); } }; absAdapter.run1(); absAdapter.run2(); } }
|
3. 应用:SpringMvc 中的 HandlerAdapter, 就使用了适配器模式
参考:设计模式 | 适配器模式及典型应用
桥接模式(Bridge 模式)
1.基本介绍
- 将实现与抽象放在两个不同的类层次中,使两个层次可以独立改变
- 是一种结构型设计模式
- 基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。
2.思路分析

3.代码
钢笔类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public abstract class Pen { protected Color color;
public Pen(Color color){ this.color= color; }
public abstract void tinting(); }
|
钢笔类扩展-小号钢笔
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class SmallPen extends Pen {
public SmallPen(Color color) { super(color); }
@Override public void tinting() { System.out.println(super.color.colour() + "小号钢笔"); }
}
|
钢笔类扩展-中号钢笔
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class MiddlePen extends Pen {
public MiddlePen(Color color) { super(color); }
@Override public void tinting() { System.out.println(super.color.colour() + "中号钢笔"); } }
|
颜色接口
1 2 3 4 5 6 7 8
|
public interface Color { String colour(); }
|
实现颜色接口 - 绿色
1 2 3 4 5 6 7
| public class Green implements Color {
@Override public String colour() { return "绿色的"; } }
|
实现颜色接口 - 红色
1 2 3 4 5 6 7
| public class Red implements Color {
@Override public String colour() { return "红色的"; } }
|
测试
1 2 3 4 5 6 7 8 9 10 11
| public class Test { public static void main(String[] args) { Pen middlePen = new MiddlePen(new Green()); middlePen.tinting();
Pen smallPen = new SmallPen(new Red()); smallPen.tinting(); } }
|
装饰者设计模式
1.基本介绍
动态地给一个对象增加一些额外的职责,增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。
2.角色
Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。
ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。
由于具体构件类和装饰类都实现了相同的抽象构件接口,因此装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。
装饰模式的核心在于抽象装饰类的设计。
3.思路分析

4.代码
抽象构件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public abstract class ABattercake {
protected abstract String getDescrible();
protected abstract int cost(); }
|
具体构件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public class Battercake extends ABattercake {
@Override protected String getDescrible() { return "煎饼"; }
@Override protected int cost() { return 8; } }
|
抽象装饰类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
public abstract class AbstractDecorator extends ABattercake { private ABattercake aBattercake;
public AbstractDecorator(ABattercake aBattercake) { this.aBattercake = aBattercake; }
protected abstract void doSomething();
@Override protected String getDescrible() { return this.aBattercake.getDescrible(); }
@Override protected int cost() { return this.aBattercake.cost(); } }
|
具体装饰类
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
|
public class EggDecorator extends AbstractDecorator { public EggDecorator(ABattercake aBattercake) { super(aBattercake); }
@Override protected void doSomething() {
}
@Override protected String getDescrible() { return super.getDescrible() + " 加一个鸡蛋"; }
@Override protected int cost() { return super.cost() + 1; }
}
|
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 SausageDecorator extends AbstractDecorator { public SausageDecorator(ABattercake aBattercake) { super(aBattercake); }
@Override protected void doSomething() {
}
@Override protected String getDescrible() { return super.getDescrible() + " 加一根香肠"; }
@Override protected int cost() { return super.cost() + 2; } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Test { public static void main(String[] args) { ABattercake aBattercake = new Battercake(); System.out.println(aBattercake.getDescrible() + ", 销售价格: " + aBattercake.cost());
aBattercake = new EggDecorator(aBattercake); System.out.println(aBattercake.getDescrible() + ", 销售价格: " + aBattercake.cost());
aBattercake = new EggDecorator(aBattercake); aBattercake = new EggDecorator(aBattercake); aBattercake = new SausageDecorator(aBattercake); System.out.println(aBattercake.getDescrible() + ", 销售价格: " + aBattercake.cost()); } }
|
参考:设计模式 | 装饰者模式及典型应用
工厂模式
简单工厂模式(Simple Factory Pattern)
1.基本介绍
定义一个工厂类,它可以 根据参数的不同返回不同类的实例,被创建的实例通常都 具有共同的父类。
2.角色
Factory(工厂角色):工厂角色即 工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以 被外界直接调用, 创建所需的产品对象;在工厂类中提供了静态的工厂方法factoryMethod(),它的返回类型为抽象产品类型Product
Product(抽象产品角色):它是 工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。
ConcreteProduct(具体产品角色):它是简单工厂模式的 创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个 具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法
3.思路分析

4.代码
抽象产品类 Video,定义了抽象方法 produce()
1 2 3
| public abstract class Video { public abstract void produce(); }
|
具体产品类 JavaVideo 和 PythonVideo,都继承了抽象产品类 Video
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class JavaVideo extends Video { @Override public void produce() { System.out.println("录制Java课程视频"); } }
public class PythonVideo extends Video { @Override public void produce() { System.out.println("录制Python课程视频"); } }
|
工厂类实现的两种方法:使用 if-else判断 和使用 反射 来创建对象
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
| public class VideoFactory {
public Video getVideo(String type) { if ("Java".equalsIgnoreCase(type)) { return new JavaVideo(); } else if ("Python".equalsIgnoreCase(type)) { return new PythonVideo(); } return null; }
public Video getVideo(Class c) { Video video = null; try { video = (Video) Class.forName(c.getName()).getDeclaredConstructor().newInstance(); } catch (Exception e) { e.printStackTrace(); } return video; } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Test { public static void main(String[] args) { VideoFactory videoFactory = new VideoFactory(); Video video1 = videoFactory.getVideo("python"); if (video1 == null) { return; } video1.produce();
Video video2 = videoFactory.getVideo(JavaVideo.class); if (video2 == null) { return; } video2.produce(); } }
|
5.适用场景
参考:设计模式 | 简单工厂模式及典型应用
工厂方法模式(Factory Method Pattern)
1.基本介绍
- 定义一个 用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个 类的实例化延迟到其子类。
- 简称为 工厂模式(Factory Pattern),又可称作 虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。
- 工厂方法模式是一种 类创建型模式。
2.角色
Product(抽象产品):它是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类
ConcreteProduct(具体产品):它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应。
Factory(抽象工厂):在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个产品。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口。
ConcreteFactory(具体工厂):它是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户端调用,返回一个具体产品类的实例。
与简单工厂模式相比,工厂方法模式最重要的区别是引入了抽象工厂角色,抽象工厂可以是接口,也可以是抽象类或者具体类
3.代码思路

4.代码
抽象工厂
1 2 3 4 5 6 7
| public abstract class VideoFactory {
public abstract Video getVideo(); }
|
具体工厂
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class JavaVideoFactory extends VideoFactory { @Override public Video getVideo() { return new JavaVideo(); } }
public class PythonVideoFactory extends VideoFactory { @Override public Video getVideo() { return new PythonVideo(); } }
|
抽象产品
1 2 3 4 5 6
| public abstract class Video {
public abstract void produce(); }
|
具体产品
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class JavaVideo extends Video { @Override public void produce() { System.out.println("录制Java课程视频"); } }
public class PythonVideo extends Video { @Override public void produce() { System.out.println("录制Python课程视频"); } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Test { public static void main(String[] args) { VideoFactory pythonVideoFactory = new PythonVideoFactory(); VideoFactory javaVideoFactory = new JavaVideoFactory();
Video pythonVideo = pythonVideoFactory.getVideo(); pythonVideo.produce();
Video javaVideo = javaVideoFactory.getVideo(); javaVideo.produce(); } }
|
当需要增加一个产品 KotlinVideo 时,只需要增加 KotlinVideo 具体产品类和 KotlinVideoFactory 具体工厂类即可,不需要修改原有的产品类和工厂类
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class KotlinVideo extends Video{ @Override public void produce() { System.out.println("录制FE课程视频"); } }
public class KotlinVideoFactory extends VideoFactory{ @Override public Video getVideo() { return new KotlinVideo(); } }
|
还可以通过反射机制和配置文件配合,连客户端代码都不需要修改
1 2 3 4 5 6 7 8
| String factoryName = "cn.coderblue.JavaVideoFactory";
Class c = Class.forName(factoryName); VideoFactory factory = (VideoFactory)c.getDeclaredConstructor().newInstance();
Video video = factory.getVideo(); video.produce();
|
参考:设计模式 | 工厂方法模式及典型应用
抽象工厂模式
1.基本介绍
- 定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类
- 可以将简单工厂模式和工厂方法模式进行整合。
- 从设计层面看,抽象工厂模式就是 对简单工厂模式的改进(或者称为进一步的抽象)。
- 将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
2.角色
AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法
ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
3.代码思路

4.代码
定义我们的抽象产品 Article 和 Video,他们是产品族的抽象类,有一个 Article 就有一个 Video
1 2 3 4 5 6 7
| public abstract class Article { public abstract void produce(); }
public abstract class Video { public abstract void produce(); }
|
具体产品 JavaArticle、PythonArticle、PythonVideo、JavaVideo
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 JavaArticle extends Article { @Override public void produce() { System.out.println("编写Java课程笔记记"); } }
public class PythonArticle extends Article { @Override public void produce() { System.out.println("编写Python课程笔记"); } }
public class JavaVideo extends Video { @Override public void produce() { System.out.println("录制Java课程视频"); } }
public class PythonVideo extends Video { @Override public void produce() { System.out.println("录制Python课程视频"); } }
|
定义我们的抽象工厂 CourseFactory,与工厂方法模式不同,工厂方法模式中一个工厂只生产一个产品,而 抽象工厂模式中一个工厂生产一族产品,有 多个工厂方法
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 JavaCourseFactory implements CourseFactory { @Override public Video getVideo() { return new JavaVideo(); }
@Override public Article getArticle() { return new JavaArticle(); } }
public class PythonCourseFactory implements CourseFactory { @Override public Video getVideo() { return new PythonVideo(); }
@Override public Article getArticle() { return new PythonArticle(); } }
|
测试:只需要指定具体工厂,就可以获取该工厂生产的一族产品
1 2 3 4 5 6 7 8 9 10 11
| public class Test { public static void main(String[] args) { CourseFactory courseFactory = new JavaCourseFactory(); Video video = courseFactory.getVideo(); Article article = courseFactory.getArticle(); video.produce(); article.produce(); } }
|
组合模式
1.基本介绍
组合多个对象形成 树形结构 以表示具有 “ 整体—部分“ 关系的层次结构。组合模式对 单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性 ,组合模式又可以称为 “整体—部分”(Part-Whole) 模式,它是一种对象结构型模式。
2.角色
Component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。
Leaf(叶子构件):它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。
Composite(容器构件):它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。
3.代码思路

4.代码
我们来实现一个简单的目录树,有文件夹和文件两种类型,首先需要一个抽象构件类,声明了文件夹类和文件类需要的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public abstract class Component {
public String getName() { throw new UnsupportedOperationException("不支持获取名称操作"); }
public void add(Component component) { throw new UnsupportedOperationException("不支持添加操作"); }
public void remove(Component component) { throw new UnsupportedOperationException("不支持删除操作"); }
public void print() { throw new UnsupportedOperationException("不支持打印操作"); }
public String getContent() { throw new UnsupportedOperationException("不支持获取内容操作"); } }
|
实现一个文件夹类 Folder,继承 Component,定义一个 List 类型的componentList属性,用来存储该文件夹下的文件和子文件夹,并实现 getName、add、remove、print等方法
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 Folder extends Component { private String name; private List<Component> componentList = new ArrayList<Component>(); public Integer level;
public Folder(String name) { this.name = name; }
@Override public String getName() { return this.name; }
@Override public void add(Component component) { this.componentList.add(component); }
@Override public void remove(Component component) { this.componentList.remove(component); }
@Override public void print() { System.out.println(this.getName()); if (this.level == null) { this.level = 1; } String prefix = ""; for (int i = 0; i < this.level; i++) { prefix += "\t- "; } for (Component component : this.componentList) { if (component instanceof Folder){ ((Folder)component).level = this.level + 1; } System.out.print(prefix); component.print(); } this.level = null; } }
|
文件类 File,继承Component父类,实现 getName、print、getContent等方法
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
| public class File extends Component { private String name; private String content;
public File(String name, String content) { this.name = name; this.content = content; }
@Override public String getName() { return this.name; }
@Override public void print() { System.out.println(this.getName()); }
@Override public String getContent() { return this.content; } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class Test { public static void main(String[] args) { Folder DSFolder = new Folder("设计模式资料"); File note1 = new File("组合模式笔记.md", "组合模式组合多个对象形成树形结构以表示具有 \"整体—部分\" 关系的层次结构"); File note2 = new File("工厂方法模式.md", "工厂方法模式定义一个用于创建对象的接口,让子类决定将哪一个类实例化。"); DSFolder.add(note1); DSFolder.add(note2);
Folder codeFolder = new Folder("样例代码"); File readme = new File("README.md", "# 设计模式示例代码项目"); Folder srcFolder = new Folder("src"); File code1 = new File("组合模式示例.java", "这是组合模式的示例代码");
srcFolder.add(code1); codeFolder.add(readme); codeFolder.add(srcFolder); DSFolder.add(codeFolder);
DSFolder.print(); } }
|
输出:
1 2 3 4 5 6 7
| 设计模式资料 组合模式笔记.md 工厂方法模式.md 样例代码 README.md src 组合模式示例.java
|
外观模式
1.基本介绍
外观模式(Facade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节
2.角色
- 外观类(Facade): 为调用端提供统一的调用接口, 外观类知道哪些子系统负责处理请求,从而将调用端的请求代理给适当子系统对象
- 调用者(Client): 外观接口的调用者
- 子系统的集合:指模块或者子系统,处理 Facade 对象指派的任务,他是功能的实际
3.代码思路

4.代码
这里我给出了两个Subsystem子系统,分别为A、B。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Facade {
SubSystemA a; SubSystemB b;
public Facade() { a = new SubSystemA(); b = new SubSystemB(); }
public void methodA() { this.a.dosomethingA(); }
public void methodB() { this.b.dosomethingB(); } }
|
Subsystem子系统角色,这里为了不过多赘述,只放上A的代码,其余子系统类似。
1 2 3 4 5 6 7
| public class SubSystemA {
public void dosomethingA() { System.out.println("子系统方法A"); }
}
|
测试
1 2 3 4 5 6 7 8 9 10
| public class Client {
public static void main(String[] args) { Facade facade = new Facade();
facade.methodA(); facade.methodB(); }
}
|
输出:
5.应用场景
享元模式
1.基本介绍
说到享元模式,第一个想到的应该就是池技术了,String常量池、数据库连接池、缓冲池等等都是享元模式的应用,所以说享元模式是池技术的重要实现方式。
比如我们每次创建字符串对象时,都需要创建一个新的字符串对象的话,内存开销会很大,所以如果第一次创建了字符串对象“adam“,下次再创建相同的字符串”adam“时,只是把它的引用指向”adam“,这样就实现了”adam“字符串再内存中的共享。
2.角色
- FlyWeight 是抽象的享元角色, 他是产品的抽象类, 同时定义出对象的外部状态和内部状态(后面介绍) 的接口或实现
- ConcreteFlyWeight 是具体的享元角色,是具体的产品类,实现抽象角色定义相关业务- UnSharedConcreteFlyWeight 是不可共享的角色,一般不会出现在享元工厂。
- FlyWeightFactory 享元工厂类,用于构建一个池容器(集合), 同时提供从池中获取对象方法
3.代码思路

4.代码
Flyweight抽象类,所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public abstract class Flyweight {
public String intrinsic; protected final String extrinsic;
public Flyweight(String extrinsic) { this.extrinsic = extrinsic; }
public abstract void operate(int extrinsic);
public String getIntrinsic() { return intrinsic; }
public void setIntrinsic(String intrinsic) { this.intrinsic = intrinsic; }
}
|
ConcreteFlyweight类,继承Flyweight超类或实现Flyweight接口,并为其内部状态增加存储空间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class ConcreteFlyweight extends Flyweight {
public ConcreteFlyweight(String extrinsic) { super(extrinsic); }
@Override public void operate(int extrinsic) { System.out.println("具体Flyweight:" + extrinsic); }
}
|
UnsharedConcreteFlyweight类,指那些不需要共享的Flyweight子类。
1 2 3 4 5 6 7 8 9 10 11 12
| public class UnsharedConcreteFlyweight extends Flyweight {
public UnsharedConcreteFlyweight(String extrinsic) { super(extrinsic); }
@Override public void operate(int extrinsic) { System.out.println("不共享的具体Flyweight:" + extrinsic); }
}
|
FlyweightFactory类,一个享元工厂,用来创建并管理Flyweight对象,主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或创建一个实例。
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 FlyweightFactory {
private static HashMap<String, Flyweight> pool = new HashMap<>();
public static Flyweight getFlyweight(String extrinsic) { Flyweight flyweight = null;
if(pool.containsKey(extrinsic)) { flyweight = pool.get(extrinsic); System.out.print("已有 " + extrinsic + " 直接从池中取---->"); } else { flyweight = new ConcreteFlyweight(extrinsic); pool.put(extrinsic, flyweight); System.out.print("创建 " + extrinsic + " 并从池中取出---->"); }
return flyweight; } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class Test {
public static void main(String[] args) { int extrinsic = 22;
Flyweight flyweightX = FlyweightFactory.getFlyweight("X"); flyweightX.operate(++ extrinsic);
Flyweight flyweightY = FlyweightFactory.getFlyweight("Y"); flyweightY.operate(++ extrinsic);
Flyweight flyweightZ = FlyweightFactory.getFlyweight("Z"); flyweightZ.operate(++ extrinsic);
Flyweight flyweightReX = FlyweightFactory.getFlyweight("X"); flyweightReX.operate(++ extrinsic);
Flyweight unsharedFlyweight = new UnsharedConcreteFlyweight("X"); unsharedFlyweight.operate(++ extrinsic); }
}
|
输出
1 2 3 4 5
| 创建 X 并从池中取出---->具体Flyweight:23 创建 Y 并从池中取出---->具体Flyweight:24 创建 Z 并从池中取出---->具体Flyweight:25 已有 X 直接从池中取---->具体Flyweight:26 不共享的具体Flyweight:27
|
5.应用场景
- 何时使用:系统中有大量对象时 或者 这些对象消耗大量内存时
- 方法:用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象,用HashMap/HashTable存储
- 应用实例:String常量池 或 数据库连接池
代理模式
1.基本介绍
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

2.三种代理模式
1.) 静态代理
创建服务类接口
1 2 3
| public interface BuyHouse { void buyHosue(); }
|
实现服务接口
1 2 3 4 5 6 7
| public class BuyHouseImpl implements BuyHouse {
@Override public void buyHosue() { System.out.println("我要买房"); } }
|
创建代理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class BuyHouseProxy implements BuyHouse {
private BuyHouse buyHouse;
public BuyHouseProxy(final BuyHouse buyHouse) { this.buyHouse = buyHouse; }
@Override public void buyHosue() { System.out.println("买房前准备"); buyHouse.buyHosue(); System.out.println("买房后装修");
} }
|
测试
1 2 3 4 5 6 7 8
| public class ProxyTest { public static void main(String[] args) { BuyHouse buyHouse = new BuyHouseImpl(); buyHouse.buyHosue(); BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse); buyHouseProxy.buyHosue(); } }
|
静态代理总结:
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
~
缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。
同时接口一旦发生改变,代理类也得相应修改。
2).动态代理
编写动态处理器
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
|
public class DynamicProxyHandler implements InvocationHandler {
private Object targetObject;
public Object newProxy(Object targetObject) { this.targetObject = targetObject; return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this); }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { checkPopedom(); Object ret = null; ret = method.invoke(targetObject, args); return ret; }
private void checkPopedom() { System.out.println("======检查权限checkPopedom()======"); } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import main.java.proxy.BuyHouse; import main.java.proxy.impl.BuyHouseImpl; import main.java.proxy.impl.DynamicProxyHandler;
import java.lang.reflect.Proxy;
public class DynamicProxyTest { public static void main(String[] args) { BuyHouse buyHouse = new BuyHouseImpl(); BuyHouse proxyBuyHouse = (BuyHouse) Proxy.newProxyInstance(BuyHouse.class.getClassLoader(), new Class[]{BuyHouse.class}, new DynamicProxyHandler(buyHouse)); proxyBuyHouse.buyHosue(); } }
|
Proxy.newProxyInstance()方法接收三个参数
static Object newProxyInstance(ClassLoader loader, Class>[] interfaces,InvocationHandler h )
~
ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
Class>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法
总结
代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理
3.CGLIB代理
创建CGLIB代理类
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 CglibProxy implements MethodInterceptor { private Object target;
public CglibProxy(Object target) { this.target = target; }
public Object getProxyInstance(){ Enhancer en = new Enhancer(); en.setSuperclass(target.getClass()); en.setCallback(this); return en.create(); }
@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("开始事务...");
Object returnValue = method.invoke(target, args); System.out.println("提交事务..."); return returnValue; } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12
| import dan.proxy.BuyHouse; import dan.proxy.impl.BuyHouseImpl; import dan.proxy.impl.CglibProxy;
public class CglibProxyTest { public static void main(String[] args){ BuyHouse buyHouse = new BuyHouseImpl(); CglibProxy cglibProxy = new CglibProxy(); BuyHouseImpl buyHouseCglibProxy = (BuyHouseImpl) cglibProxy.getInstance(buyHouse); buyHouseCglibProxy.buyHosue(); } }
|
总结
- CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。
- 对于单例的对象,因为 无需频繁创建对象,用CGLIB合适 ,反之使用JDK方式要更为合适一些。
- 由于CGLib由于是采用 动态创建子类的方法,对于final修饰的方法无法进行代理 。
- 继承只能使用CGLib,因为JDK代理生成的代理类,默认会继承一个类,由于java是单继承,所以当原始类继承一个类的时候,只能使用CGLib动态代理
- 底层是通过使用字节码处理框架 ASM 来转换字节码并生成新的类
访问者模式
迭代器模式
观察者模式
1.基本介绍
观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个 主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

2.角色
- Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
- ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
- Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
- ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
3.代码
抽象观察者,里面定义了一个更新的方法
1 2 3
| public interface Observer { public void update(String message); }
|
具体观察者(ConcrereObserver),微信用户是观察者,里面实现了更新的方法:
1 2 3 4 5 6 7 8 9 10 11
| public class WeixinUser implements Observer { private String name; public WeixinUser(String name) { this.name = name; } @Override public void update(String message) { System.out.println(name + "-" + message); } }
|
抽象被观察者(Subject),抽象主题,提供了attach、detach、notify三个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public interface Subject {
public void attach(Observer observer);
public void detach(Observer observer);
public void notify(String message); }
|
具体被观察者(ConcreteSubject),微信公众号是具体主题(具体被观察者),里面存储了订阅该公众号的微信用户,并实现了抽象主题中的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public class SubscriptionSubject implements Subject { private List<Observer> weixinUserlist = new ArrayList<Observer>();
@Override public void attach(Observer observer) { weixinUserlist.add(observer); }
@Override public void detach(Observer observer) { weixinUserlist.remove(observer); }
@Override public void notify(String message) { for (Observer observer : weixinUserlist) { observer.update(message); } } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Client { public static void main(String[] args) { WeixinUser user1 = new WeixinUser("杨影枫"); WeixinUser user2 = new WeixinUser("月眉儿"); WeixinUser user3 = new WeixinUser("紫轩");
SubscriptionSubject mSubscriptionSubject=new SubscriptionSubject(); mSubscriptionSubject.attach(user1); mSubscriptionSubject.attach(user2); mSubscriptionSubject.attach(user3);
mSubscriptionSubject.notify("廖雪峰的专栏更新了"); } }
|
输出
1 2 3
| 杨影枫-刘望舒的专栏更新了 月眉儿-刘望舒的专栏更新了 紫轩-刘望舒的专栏更新了
|
总结
中介者模式
备忘录模式
解释器模式
状态模式
策略模式
职责链模式