首页 > 代码库 > 设计模式笔记——GoF设计模式汇总
设计模式笔记——GoF设计模式汇总
目录
· 总述
· 记忆
· 效果
· 面向对象设计原则
· 创建型模式
· 单例模式(Singleton)
· 效果
· 分类
· 代码(饿汉式)
· 代码(懒汉式)
· 代码(双重检测锁式)
· 代码(静态内部类式)
· 代码(枚举单例)
· 代码(使用反射的破解与防御)
· 代码(使用序列化的破解与防御)
· 应用场景
· 工厂模式
· 效果
· 分类
· 代码(简单工厂)
· 代码(工厂方法)
· 代码(抽象工厂)
· 应用场景
· 构建者模式(Builder)
· 效果
· 代码
· 应用场景
· 原型模式(Prototype)
· 效果
· 核心角色
· 代码(浅克隆)
· 代码(基于JDK的深克隆)
· 代码(基于序列化的深克隆)
· 应用场景
· 结构型模式
· 适配器模式(Adapter)
· 效果
· 核心角色
· 分类
· 代码(使用继承)
· 代码(使用关联)
· 应用场景
· 代理模式(Proxy)
· 效果
· 核心角色
· 分类
· 代码(静态代理)
· 代码(动态代理)
· 应用场景
· 桥接模式(Bridge)
· 效果
· 代码
· 应用场景
· 组合模式(Composite)
· 效果
· 核心角色
· 代码
· 代码(杀毒举例)
· 应用场景
· 装饰器模式(Decorator)
· 效果
· 核心角色
· 代码
· 应用场景
· 外观模式(Facade)
· 效果
· 代码
· 应用场景
· 享元模式(FlyWeight)
· 效果
· 核心角色
· 代码
· 应用场景
· 行为型模式
· 责任链模式(Chain of Resposibility)
· 效果
· 核心角色
· 代码
· 应用场景
· 迭代器模式(Iterator)
· 效果
· 核心角色
· 代码
· 应用场景
· 中介者模式(Mediator)
· 效果
· 代码
· 应用场景
· 命令模式(Command)
· 效果
· 核心角色
· 代码
· 应用场景
· 解释器模式(Interpreter)
· 效果
· 应用场景
· 访问者模式(Visitor)
· 效果
· 应用场景
· 策略模式(Strategy)
· 效果
· 代码
· 应用场景
· 模板方法模式(Template Method)
· 效果
· 代码
· 应用场景
· 状态模式(State)
· 效果
· 核心角色
· 代码
· 应用场景
· 观察者模式(Observer)
· 效果
· 代码
· 代码(基于JDK)
· 应用场景
· 备忘录模式(Memento)
· 效果
· 核心角色
· 代码
· 应用场景
总述
记忆
1. 创建型:bpfs;
2. 结构型:abcdffp;
3. 行为型:iimmccsstov。
效果
1. 所有面向对象设计原则和设计模式都是为了降低代码耦合度,提高扩展性、复用,手段是“分工”。
2. 类似社会分工,现代社会比原始社会发展得大,也是因为分工。
面向对象设计原则
1. OCP(开闭原则,Open Closed Principle):一个软件的实体应当对扩展开放,对修改关闭。
2. DIP(依赖倒转原则,Dependence Inversion Principle):要针对接口编程,不要针对实现编程。
3. LoD(迪米特法则,Law of Demeter):只与你直接的朋友通信,而避免和陌生人通信。
创建型模式
单例模式(Singleton)
效果
1. 保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
2. 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
分类
1. 常见实现方式。
a) 饿汉式:线程安全,调用效率高,不能延时加载。
b) 懒汉式:线程安全,调用效率不高,可延时加载。
2. 其他实现方式。
a) 双重检测锁式:由于JVM底层内部模型原因,偶尔出问题,不建议使用。
b) 静态内部类式:线程安全,调用效率高,可延时加载。
c) 枚举单例:线程安全,调用效率高,不能延时加载。
3. 选择方法。
a) 单例对象占用资源少,不需要延时加载:枚举式好于饿汉式;
b) 单例对象占用资源多,需要延时加载:静态内部类好于懒汉式。
代码(饿汉式)
1. Singleton.java
1 public class Singleton { 2 3 // 类初始化时立即创建对象 4 private static final Singleton instance = new Singleton(); 5 6 // 私有化构造器 7 private Singleton() { 8 if (instance != null) { 9 throw new RuntimeException();10 }11 }12 13 public static Singleton getInstance() {14 return instance;15 }16 17 }
2. Client.java
1 public class Client {2 3 public static void main(String[] args) {4 Singleton singleton1 = Singleton.getInstance();5 Singleton singleton2 = Singleton.getInstance();6 System.out.println(singleton1 == singleton2);7 }8 9 }
代码(懒汉式)
1. Singleton.java
1 public class Singleton { 2 3 private static Singleton instance; 4 5 // 私有化构造器 6 private Singleton() { 7 } 8 9 // 同步方法10 public static synchronized Singleton getInstance() {11 if (instance == null) {12 // 延时加载13 instance = new Singleton();14 }15 return instance;16 }17 18 }
2. Client.java
1 public class Client {2 3 public static void main(String[] args) {4 Singleton singleton1 = Singleton.getInstance();5 Singleton singleton2 = Singleton.getInstance();6 System.out.println(singleton1 == singleton2);7 }8 9 }
代码(双重检测锁式)
1. Singleton.java
1 public class Singleton { 2 3 private static volatile Singleton instance; 4 5 // 私有化构造器 6 private Singleton() { 7 } 8 9 public static Singleton getInstance() {10 if (instance == null) {11 // 第一次创建时同步12 synchronized (Singleton.class) {13 if (instance == null) {14 // 延时加载15 instance = new Singleton();16 }17 }18 }19 return instance;20 }21 22 }
2. Client.java
1 public class Client {2 3 public static void main(String[] args) {4 Singleton singleton1 = Singleton.getInstance();5 Singleton singleton2 = Singleton.getInstance();6 System.out.println(singleton1 == singleton2);7 }8 9 }
代码(静态内部类式)
1. Singleton.java
1 public class Singleton { 2 3 // 初始化外部类时不会立即初始化内部类 4 private static class SingletonInstance { 5 private static final Singleton instance = new Singleton(); 6 } 7 8 // 私有化构造器 9 private Singleton() {10 }11 12 public static Singleton getInstance() {13 return SingletonInstance.instance;14 }15 16 }
2. Client.java
1 public class Client {2 3 public static void main(String[] args) {4 Singleton singleton1 = Singleton.getInstance();5 Singleton singleton2 = Singleton.getInstance();6 System.out.println(singleton1 == singleton2);7 }8 9 }
代码(枚举单例)
1. Singleton.java
1 public enum Singleton { 2 3 // 枚举本身就是单例 4 INSTANCE; 5 6 // 添加需要的方法 7 public void method() { 8 } 9 10 }
2. Client.java
1 public class Client {2 3 public static void main(String[] args) {4 Singleton singleton1 = Singleton.INSTANCE;5 Singleton singleton2 = Singleton.INSTANCE;6 System.out.println(singleton1 == singleton2);7 }8 9 }
代码(使用反射的破解与防御)
1. Singleton.java
1 public class Singleton { 2 3 // 类初始化时立即创建对象 4 private static final Singleton instance = new Singleton(); 5 6 // 私有化构造器 7 private Singleton() { 8 // 防御:再次创建时抛出异常 9 if (instance != null) {10 throw new RuntimeException();11 }12 }13 14 public static Singleton getInstance() {15 return instance;16 }17 18 }
2. Client.java
1 import java.lang.reflect.Constructor; 2 3 public class Client { 4 5 public static void main(String[] args) throws Exception { 6 Singleton singleton1 = Singleton.getInstance(); 7 8 Class<Singleton> clazz = Singleton.class; 9 Constructor<Singleton> constructor = clazz.getDeclaredConstructor();10 constructor.setAccessible(true);11 Singleton singleton2 = constructor.newInstance();12 System.out.println(singleton1 == singleton2);13 }14 15 }
代码(使用序列化的破解与防御)
1. Singleton.java
1 import java.io.Serializable; 2 3 public class Singleton implements Serializable { 4 5 private static final long serialVersionUID = -3230831923851678463L; 6 7 // 类初始化时立即创建对象 8 private static final Singleton instance = new Singleton(); 9 10 // 私有化构造器11 private Singleton() {12 }13 14 public static Singleton getInstance() {15 return instance;16 }17 18 // 防御:反序列化时,直接返回该方法的返回值19 private Object readResolve() {20 return instance;21 }22 23 }
2. Client.java
1 import java.io.File; 2 import java.io.FileInputStream; 3 import java.io.FileOutputStream; 4 import java.io.ObjectInputStream; 5 import java.io.ObjectOutputStream; 6 7 public class Client { 8 9 public static void main(String[] args) throws Exception {10 Singleton singleton1 = Singleton.getInstance();11 12 File tempFile = new File("D:/test");13 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(tempFile));14 oos.writeObject(singleton1);15 oos.close();16 ObjectInputStream ios = new ObjectInputStream(new FileInputStream(tempFile));17 Singleton singleton2 = (Singleton) ios.readObject();18 ios.close();19 System.out.println(singleton1 == singleton2);20 21 }22 23 }
应用场景
1. Windows的Task Manager(任务管理器)。
2. Windows的Recycle Bin(回收站)。
3. 项目中,读取配置文件的类,一般只有一个对象,没必要每次创建。
4. 数据库连接池。
5. Application是单例的典型应用(Servlet编程)。
6. Spring中,每个Bean默认是单例的。
7. 每个Servlet是单例。
8. Spring MVC中,控制器对象是单例的。
工厂模式
效果
1. 实例化对象,用工厂方法代替new。实现了创建者和调用者的分离。
2. 将选择实现类、创建对象统一管理和控制,从而将调用者跟我们的实现类解耦。
分类
1. 简单工厂模式:用来产生同一等级结构中的任意产品。对于增加新的产品,需要修改已有代码。
2. 工厂方法模式:用来产生同一等级结构中的固定产品。支持增加任意产品。
3. 抽象工厂模式:用来生产不同产品族的全部产品。对于增加新的产品,无能为力;支持增加产品族。
4. 简单工厂模式效果:
a) 又称静态工厂模式。
b) 工厂类一般使用静态方法,通过接收的参数来返回不同的对象实例。
c) 对于增加新产品只能修改代码(违反OCP)。
d) 有两种实现方式(见代码)。
5. 工厂方法模式效果:
a) 避免简单工厂的缺点,但不完全满足OCP。
b) 简单工厂模式VS.工厂方法模式:
i. 结构复杂度:显然简单工厂模式占优,简单工厂模式只要一个工厂,而工厂方法模式的工厂类随着产品类个数增加而增加。
ii. 代码复杂度:代码复杂度与结构复杂度相反,简单工厂模式的工厂类随着产品增加需要增加更多方法(代码),而工厂方法模式每个具体工厂类只完成单一任务,代码简单。
iii. 客户端编程难度:工厂方法模式虽然满足了OCP,但客户端编码中需要对工厂实例化,而简单工厂模式的工厂类是一个静态类。
iv. 管理上的难度:工厂方法模式需要维护的工厂类过多,而简单工厂模式只有一个。
c) 设计理论建议使用工厂方法模式,但实际中一般都用简单工厂模式。
6. 抽象工厂模式效果:
a) 用来生产不同产品族的全部产品。对于增加新的产品,无能为力;支持增加产品族。
b) 抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象时一种非常好的解决方式。
代码(简单工厂)
1. Car.java
1 public interface Car {2 3 void run();4 5 }
2. Audi.java
1 public class Audi implements Car {2 3 @Override4 public void run() {5 System.out.println("奥迪在跑!");6 }7 8 }
3. Byd.java
1 public class Byd implements Car {2 3 @Override4 public void run() {5 System.out.println("比亚迪在跑!");6 }7 8 }
4. CarFactory.java
1 // 一个方法实现 2 public class CarFactory1 { 3 4 public static Car createCar(String type) { 5 if ("Audi".equals(type)) { 6 return new Audi(); 7 } 8 if ("Byd".equals(type)) { 9 return new Byd();10 }11 return null;12 }13 14 }
5. CarFactory2.java
1 // 多个方法实现 2 public class CarFactory2 { 3 4 public static Car createAudi() { 5 return new Audi(); 6 } 7 8 public static Car createByd() { 9 return new Byd();10 }11 12 }
6. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 Car car1 = CarFactory1.createCar("Audi"); 5 Car car2 = CarFactory1.createCar("Byd"); 6 car1.run(); 7 car2.run(); 8 } 9 10 }
代码(工厂方法)
1. Car.java
1 public interface Car {2 3 void run();4 5 }
2. CarFactory.java
1 public interface CarFactory {2 3 Car createCar();4 5 }
3. Audi.java
1 public class Audi implements Car {2 3 @Override4 public void run() {5 System.out.println("奥迪在跑!");6 }7 8 }
4. AudiFactory.java
1 public class AudiFactory implements CarFactory {2 3 @Override4 public Car createCar() {5 return new Audi();6 }7 8 }
5. Byd.java
1 public class Byd implements Car {2 3 @Override4 public void run() {5 System.out.println("比亚迪在跑!");6 }7 8 }
6. BydFactory.java
1 public class BydFactory implements CarFactory {2 3 @Override4 public Car createCar() {5 return new Byd();6 }7 8 }
7. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 Car car1 = new AudiFactory().createCar(); 5 Car car2 = new BydFactory().createCar(); 6 car1.run(); 7 car2.run(); 8 } 9 10 }
代码(抽象工厂)
1. Engine.java
1 public interface Engine { 2 3 void start(); 4 5 void speedUp(); 6 7 } 8 9 class LuxuryEngine implements Engine {10 11 @Override12 public void start() {13 System.out.println("快速启动!");14 }15 16 @Override17 public void speedUp() {18 System.out.println("快速加速!");19 }20 21 }22 23 class LowEngine implements Engine {24 25 @Override26 public void start() {27 System.out.println("慢速启动!");28 }29 30 @Override31 public void speedUp() {32 System.out.println("慢速加速!");33 }34 35 }
2. Seat.java
1 public interface Seat { 2 3 void massage(); 4 5 } 6 7 class LuxurySeat implements Seat { 8 9 @Override10 public void massage() {11 System.out.println("按摩!");12 }13 14 }15 16 class LowSeat implements Seat {17 18 @Override19 public void massage() {20 System.out.println("不能按摩!");21 }22 23 }
3. Tire.java
1 public interface Tire { 2 3 void revolve(); 4 5 } 6 7 class LuxuryTire implements Tire { 8 9 @Override10 public void revolve() {11 System.out.println("旋转不磨损!");12 }13 14 }15 16 class LowTire implements Tire {17 18 @Override19 public void revolve() {20 System.out.println("旋转磨损快!");21 }22 23 }
4. CarFactory.java
1 public interface CarFactory { 2 3 Engine createEngine(); 4 5 Seat createSeat(); 6 7 Tire createTire(); 8 9 }10 11 class LuxuryCarFactory implements CarFactory {12 13 @Override14 public Engine createEngine() {15 return new LuxuryEngine();16 }17 18 @Override19 public Seat createSeat() {20 return new LuxurySeat();21 }22 23 @Override24 public Tire createTire() {25 return new LuxuryTire();26 }27 28 }29 30 class LowCarFactory implements CarFactory {31 32 @Override33 public Engine createEngine() {34 return new LowEngine();35 }36 37 @Override38 public Seat createSeat() {39 return new LowSeat();40 }41 42 @Override43 public Tire createTire() {44 return new LowTire();45 }46 47 }
5. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 CarFactory carFactory = new LuxuryCarFactory(); 5 Engine engine = carFactory.createEngine(); 6 engine.start(); 7 engine.speedUp(); 8 } 9 10 }
应用场景
1. JDK中Calendar.getInstance()方法。
2. JDBC中Connection对象的获取。
3. Hibernate中SessionFactory创建Session。
4. Spring中IoC容器创建管理Bean对象。
5. 反射中Class对象的newInstance()方法。
构建者模式(Builder)
效果
1. 构建一个复杂的产品(如神舟飞船、iPhone)时,需要解决“如何装配子组件”的问题。
2. 分离了对象子组件的单独构建(Builder)和装配(Director),从而构造出复杂对象。
3. 由于实现了构建和装配的解耦。不同的构建器、相同的装配,或者相同的构建器、不同的装配,都可以创建不同的对象。
4. 建造者模式一般与工厂模式搭配,由工厂模式创建子组件,再有建造者模式装配。
代码
1. Airship.java
1 public class Airship { 2 3 private Engine engine; 4 5 private OrbitalModule orbitalModule; 6 7 private EscapeTower escapeTower; 8 9 public void launch() {10 System.out.println(engine.getName() + "点火!");11 System.out.println(orbitalModule.getName() + "发射!");12 }13 14 public Engine getEngine() {15 return engine;16 }17 18 public void setEngine(Engine engine) {19 this.engine = engine;20 }21 22 public OrbitalModule getOrbitalModule() {23 return orbitalModule;24 }25 26 public void setOrbitalModule(OrbitalModule orbitalModule) {27 this.orbitalModule = orbitalModule;28 }29 30 public EscapeTower getEscapeTower() {31 return escapeTower;32 }33 34 public void setEscapeTower(EscapeTower escapeTower) {35 this.escapeTower = escapeTower;36 }37 38 }39 40 class Engine {41 42 private String name;43 44 public String getName() {45 return name;46 }47 48 public void setName(String name) {49 this.name = name;50 }51 52 }53 54 class OrbitalModule {55 56 private String name;57 58 public String getName() {59 return name;60 }61 62 public void setName(String name) {63 this.name = name;64 }65 66 }67 68 class EscapeTower {69 70 private String name;71 72 public String getName() {73 return name;74 }75 76 public void setName(String name) {77 this.name = name;78 }79 80 }
2. AirshipBuilder.java
1 public interface AirshipBuilder {2 3 Engine buildEngine();4 5 OrbitalModule buildOrbitalModule();6 7 EscapeTower buildEscapeTower();8 9 }
3. AirshipDirector.java
1 public interface AirshipDirector {2 3 Airship directAirship();4 5 }
4. SzAirshipBuilder.java
1 public class SzAirshipBuilder implements AirshipBuilder { 2 3 @Override 4 public Engine buildEngine() { 5 // 也可使用工厂模式创建 6 Engine engine = new Engine(); 7 engine.setName("神舟发动机"); 8 return engine; 9 }10 11 @Override12 public OrbitalModule buildOrbitalModule() {13 // 也可使用工厂模式创建14 OrbitalModule orbitalModule = new OrbitalModule();15 orbitalModule.setName("神舟轨道舱");16 return orbitalModule;17 }18 19 @Override20 public EscapeTower buildEscapeTower() {21 // 也可使用工厂模式创建22 EscapeTower escapeTower = new EscapeTower();23 escapeTower.setName("神舟逃逸塔");24 return escapeTower;25 }26 27 }
5. SzAirshipDirector.java
1 public class SzAirshipDirector implements AirshipDirector { 2 3 private AirshipBuilder airshipBuilder; 4 5 public SzAirshipDirector(AirshipBuilder airshipBuilder) { 6 this.airshipBuilder = airshipBuilder; 7 } 8 9 @Override10 public Airship directAirship() {11 Engine engine = airshipBuilder.buildEngine();12 OrbitalModule orbitalModule = airshipBuilder.buildOrbitalModule();13 EscapeTower escapeTower = airshipBuilder.buildEscapeTower();14 15 Airship airship = new Airship();16 airship.setEngine(engine);17 airship.setOrbitalModule(orbitalModule);18 airship.setEscapeTower(escapeTower);19 20 return airship;21 }22 23 }
6. Client.java
1 public class Client {2 3 public static void main(String[] args) {4 AirshipDirector airshipDirector = new SzAirshipDirector(new SzAirshipBuilder());5 Airship airship = airshipDirector.directAirship();6 airship.launch();7 }8 9 }
应用场景
1. StringBuilder.append()方法。
2. SQL中的PareparedStatement。
原型模式(Prototype)
效果
1. 通过new创建对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
2. 就是Java中的克隆技术,以某个对象为原型,复制出新的对象。
3. 优势:效率高,避免重新执行构建过程。
4. 克隆类似于new,但不同于new。new创建新的对象属性采用默认值。克隆出的对象属性完全与原型对象相同,并且克隆出的新对象改变不会影响原型对象,然后再修改克隆对象的值。
核心角色
1. Clonable接口的clone()方法。
2. 实现原型模式最困难的是内存复制操作,所幸Java提供了clone()方法。
代码(浅克隆)
1. Sheep.java
1 import java.util.Date; 2 3 public class Sheep implements Cloneable { 4 5 private String name; 6 7 private Date birthday; 8 9 @Override10 protected Object clone() throws CloneNotSupportedException {11 return super.clone();12 }13 14 public String getName() {15 return name;16 }17 18 public void setName(String name) {19 this.name = name;20 }21 22 public Date getBirthday() {23 return birthday;24 }25 26 public void setBirthday(Date birthday) {27 this.birthday = birthday;28 }29 30 }
2. Client.java
1 import java.util.Date; 2 3 public class Client { 4 5 public static void main(String[] args) throws Exception { 6 Sheep sheep1 = new Sheep(); 7 sheep1.setName("少利"); 8 sheep1.setBirthday(new Date()); 9 10 Sheep sheep2 = (Sheep) sheep1.clone();11 sheep2.setName("多利");12 System.out.println(sheep2.getName());13 System.out.println(sheep2.getBirthday());14 15 // 浅克隆16 System.out.println(sheep1.getBirthday() == sheep2.getBirthday());17 }18 19 }
代码(基于JDK的深克隆)
1. Sheep.java
1 import java.util.Date; 2 3 public class Sheep implements Cloneable { 4 5 private String name; 6 7 private Date birthday; 8 9 @Override10 protected Object clone() throws CloneNotSupportedException {11 Sheep sheep = (Sheep) super.clone();12 sheep.setBirthday((Date) birthday.clone());13 return sheep;14 }15 16 public String getName() {17 return name;18 }19 20 public void setName(String name) {21 this.name = name;22 }23 24 public Date getBirthday() {25 return birthday;26 }27 28 public void setBirthday(Date birthday) {29 this.birthday = birthday;30 }31 32 }
2. Client.java
1 import java.util.Date; 2 3 public class Client { 4 5 public static void main(String[] args) throws Exception { 6 Sheep sheep1 = new Sheep(); 7 sheep1.setName("少利"); 8 sheep1.setBirthday(new Date()); 9 10 Sheep sheep2 = (Sheep) sheep1.clone();11 sheep2.setName("多利");12 System.out.println(sheep2.getName());13 System.out.println(sheep2.getBirthday());14 15 // 深克隆16 System.out.println(sheep1.getBirthday() == sheep2.getBirthday());17 }18 19 }
代码(基于序列化的深克隆)
1. Sheep.java
1 import java.io.ByteArrayInputStream; 2 import java.io.ByteArrayOutputStream; 3 import java.io.IOException; 4 import java.io.ObjectInputStream; 5 import java.io.ObjectOutputStream; 6 import java.io.Serializable; 7 import java.util.Date; 8 9 public class Sheep implements Cloneable, Serializable {10 11 private static final long serialVersionUID = 2155997264135266066L;12 13 private String name;14 15 private Date birthday;16 17 @Override18 protected Object clone() throws CloneNotSupportedException {19 Sheep sheep = null;20 ByteArrayOutputStream baos = null;21 ObjectOutputStream oos = null;22 ByteArrayInputStream bais = null;23 ObjectInputStream ois = null;24 try {25 baos = new ByteArrayOutputStream();26 oos = new ObjectOutputStream(baos);27 oos.writeObject(this);28 byte[] bytes = baos.toByteArray();29 bais = new ByteArrayInputStream(bytes);30 ois = new ObjectInputStream(bais);31 sheep = (Sheep) ois.readObject();32 33 } catch (IOException | ClassNotFoundException e) {34 e.printStackTrace();35 }36 return sheep;37 }38 39 public String getName() {40 return name;41 }42 43 public void setName(String name) {44 this.name = name;45 }46 47 public Date getBirthday() {48 return birthday;49 }50 51 public void setBirthday(Date birthday) {52 this.birthday = birthday;53 }54 55 }
2. Client.java
1 import java.util.Date; 2 3 public class Client { 4 5 public static void main(String[] args) throws Exception { 6 Sheep sheep1 = new Sheep(); 7 sheep1.setName("少利"); 8 sheep1.setBirthday(new Date()); 9 10 Sheep sheep2 = (Sheep) sheep1.clone();11 sheep2.setName("多利");12 System.out.println(sheep2.getName());13 System.out.println(sheep2.getBirthday());14 15 // 深克隆16 System.out.println(sheep1.getBirthday() == sheep2.getBirthday());17 }18 19 }
应用场景
1. 原型模式很少单独使用,一般与工厂模式一起出现。通过clone()方法创建对象后由工厂模式返回。
2. Spring的Bean创建有单例模式和原型模式两种方式。
结构型模式
适配器模式(Adapter)
效果
将一个类的接口转换成客户希望的另一个接口,使原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
核心角色
1. 目标接口(Target):客户所期望的接口(接口、抽象类或具体类)。
2. 适配的类(Adaptee)。
3. 适配器(Adapter):通过包装适配的类,把原接口转换成目标接口。
分类
1. 使用继承实现:Adapter继承Adaptee。
2. 使用关联实现:Adapter持有Adaptee的引用,Adapter可以继承其他类,更灵活。
代码(使用继承)
1. Target.java
1 public interface Target {2 3 void handleRequest();4 5 }
2. Adaptee.java
1 public class Adaptee {2 3 public void request() {4 System.out.println("处理请求!");5 }6 7 }
3. Adapter.java
1 public class Adapter extends Adaptee implements Target {2 3 @Override4 public void handleRequest() {5 request();6 }7 8 }
4. Client.java
1 public class Client { 2 3 public void execute(Target target) { 4 target.handleRequest(); 5 } 6 7 public static void main(String[] args) { 8 Target target = new Adapter(); 9 new Client().execute(target);10 }11 12 }
代码(使用关联)
1. Target.java
1 public interface Target {2 3 void handleRequest();4 5 }
2. Adaptee.java
1 public class Adaptee {2 3 public void request() {4 System.out.println("处理请求!");5 }6 7 }
3. Adapter.java
1 public class Adapter implements Target { 2 3 // 使用关联更灵活,这样适配器可以继承其他类 4 private Adaptee adaptee; 5 6 public Adapter(Adaptee adaptee) { 7 this.adaptee = adaptee; 8 } 9 10 @Override11 public void handleRequest() {12 adaptee.request();13 }14 15 }
4. Client.java
1 public class Client { 2 3 public void execute(Target target) { 4 target.handleRequest(); 5 } 6 7 public static void main(String[] args) { 8 Target target = new Adapter(); 9 new Client().execute(target);10 }11 12 }
应用场景
1. 做旧系统改造和升级。
2. java.io.InputStreamReader(InputStream)。
3. java.io.OutputStreamWriter(OutputStream)。
代理模式(Proxy)
效果
1. 通过代理,控制对对象的访问。
2. 可以详细控制访问某个(某类)对象的方法,在调用方法前做前置处理,调用方法后做后置处理(即APO的微观实现)。
3. AOP(Aspect Oriented Programming,面向切面编程)的核心实现机制。
核心角色
1. 抽象角色:定义代理角色和真实角色的公共对外方法。
2. 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
3. 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己操作。
分类
1. 静态代理(静态定义代理类)。
2. 动态代理(动态定义代理类):
a) JDK自带的动态代理(java.lang.reflect.Proxy动态生成代理类和对象,java.lang.reflect.InvocationHandler通过invoke()方法实现访问真实角色);
b) javaassist字节码操作库实现;
c) CGLIB;
d) ASM(底层使用指令,可维护性较差)。
代码(静态代理)
1. Star.java
1 public interface Star { 2 3 void confer(); 4 5 void signContract(); 6 7 void bookTicket(); 8 9 void sing();10 11 void collectMoney();12 13 }
2. RealStar.java
1 public class RealStar implements Star { 2 3 @Override 4 public void confer() { 5 System.out.println("RealStar.confer()"); 6 } 7 8 @Override 9 public void signContract() {10 System.out.println("RealStar.signContract()");11 }12 13 @Override14 public void bookTicket() {15 System.out.println("RealStar.bookTicket()");16 }17 18 @Override19 public void sing() {20 System.out.println("RealStar.sing()");21 }22 23 @Override24 public void collectMoney() {25 System.out.println("RealStar.collectMoney()");26 }27 28 }
3. ProxyStar.java
1 public class ProxyStar implements Star { 2 3 private Star realStar; 4 5 public ProxyStar(Star realStar) { 6 this.realStar = realStar; 7 } 8 9 @Override10 public void confer() {11 System.out.println("ProxyStar.confer()");12 }13 14 @Override15 public void signContract() {16 System.out.println("ProxyStar.signContract()");17 }18 19 @Override20 public void bookTicket() {21 System.out.println("ProxyStar.bookTicket()");22 }23 24 @Override25 public void sing() {26 realStar.sing();27 }28 29 @Override30 public void collectMoney() {31 System.out.println("ProxyStar.collectMoney()");32 }33 34 }
4. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 RealStar realStar = new RealStar(); 5 ProxyStar proxyStar = new ProxyStar(realStar); 6 proxyStar.confer(); 7 proxyStar.signContract(); 8 proxyStar.bookTicket(); 9 proxyStar.sing();10 proxyStar.collectMoney();11 }12 13 }
代码(动态代理)
1. Star.java
1 public interface Star { 2 3 void confer(); 4 5 void signContract(); 6 7 void bookTicket(); 8 9 void sing();10 11 void collectMoney();12 13 }
2. RealStar.java
1 public class RealStar implements Star { 2 3 @Override 4 public void confer() { 5 System.out.println("RealStar.confer()"); 6 } 7 8 @Override 9 public void signContract() {10 System.out.println("RealStar.signContract()");11 }12 13 @Override14 public void bookTicket() {15 System.out.println("RealStar.bookTicket()");16 }17 18 @Override19 public void sing() {20 System.out.println("RealStar.sing()");21 }22 23 @Override24 public void collectMoney() {25 System.out.println("RealStar.collectMoney()");26 }27 28 }
3. StarHandler.java
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 4 public class StarHandler implements InvocationHandler { 5 6 private Star realStar; 7 8 public StarHandler(Star realStar) { 9 this.realStar = realStar;10 }11 12 @Override13 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {14 switch (method.getName()) {15 case "confer":16 System.out.println("ProxyStar.confer()");17 break;18 case "signContract":19 System.out.println("ProxyStar.signContract()");20 break;21 case "bookTicket":22 System.out.println("ProxyStar.bookTicket()");23 break;24 case "sing":25 method.invoke(realStar, args);26 break;27 case "collectMoney":28 System.out.println("ProxyStar.collectMoney()");29 break;30 }31 32 return null;33 }34 35 }
4. Client.java
1 import java.lang.reflect.Proxy; 2 3 public class Client { 4 5 public static void main(String[] args) { 6 Star realStar = new RealStar(); 7 StarHandler handler = new StarHandler(realStar); 8 Star proxyStar = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] { Star.class }, handler); 9 proxyStar.confer();10 proxyStar.signContract();11 proxyStar.bookTicket();12 proxyStar.sing();13 proxyStar.collectMoney();14 }15 16 }
应用场景
1. 安全代理:屏蔽对真实角色的直接访问。
2. 远程代理:通过代理类处理远程方法调用(RMI)。
3. 延迟代理:先加载轻量级代理对象,真正需要时再加载真实对象。
桥接模式(Bridge)
效果
1. 处理多层继承结构、处理多维变化的场景,将各个维度设计成独立的继承结构,使各个维度可以独立的扩展在抽象层建立关联。
2. 以商场系统中的电脑分类为例,多层继承不利于扩展性(类个数膨胀问题):
a) 如果要增加一个新的电脑类型智能手机,则要增加各个品牌下面的类。
b) 如果要增加一个新的品牌,也要增加各种电脑类型的类。
3. 违反单一职责原则:比如一个联想笔记本,有两个引起这个类变化的原因。
4. 桥接模式将电脑拆分为类型和品牌两个维度。
代码
1. Computer.java
1 public abstract class Computer { 2 3 protected Brand brand; 4 5 public Computer(Brand brand) { 6 this.brand = brand; 7 } 8 9 public abstract void run();10 11 }12 13 class Desktop extends Computer {14 15 public Desktop(Brand brand) {16 super(brand);17 }18 19 @Override20 public void run() {21 System.out.println(brand.getName() + "台式机运行!");22 }23 24 }25 26 class Laptop extends Computer {27 28 public Laptop(Brand brand) {29 super(brand);30 }31 32 @Override33 public void run() {34 System.out.println(brand.getName() + "笔记本运行!");35 }36 37 }
2. Brand.java
1 public interface Brand { 2 3 String getName(); 4 5 } 6 7 class Lenovo implements Brand { 8 9 @Override10 public String getName() {11 return "联想";12 }13 14 }15 16 class Dell implements Brand {17 18 @Override19 public String getName() {20 return "戴尔";21 }22 23 }
3. Client.java
1 public class Client {2 3 public static void main(String[] args) {4 Brand brand = new Lenovo();5 Computer computer = new Laptop(brand);6 computer.run();7 }8 9 }
应用场景
1. JDBC驱动程序。
2. 银行日志管理。
a) 格式分类:操作日志、交易日志、异常日志。
b) 距离分类:本地记录日志、异地记录日志。
3. 人力资源系统的奖金计算模块。
a) 奖金分类:个人奖金、团体奖金、激励奖金。
b) 部门分类:人事部门、销售部门、研发部门。
4. OA系统的消息处理。
a) 业务类型:普通消息、加急消息、特急消息。
b) 发送消息方式:系统内消息、手机短信、邮件。
组合模式(Composite)
效果
1. 把部分和整理的关系用树形结构表示,从而使客户端可以使用统一方式处理部分对象和整体对象。
2. 组合模式为处理树形结构提供了完美的解决方案,描述了如何将容器和叶子进行递归组合,使得用户在使用时可以一致性的对待容器和叶子。
核心角色
1. 抽象构件角色(Component):定义了叶子和容器构件的共同点。
2. 叶子构件角色(Leaf):无子节点。
3. 容器构件角色(Composite):有容器特征,可以包含子节点。
代码
Component.java
1 import java.util.List; 2 3 public interface Component { 4 5 void operation(); 6 7 } 8 9 interface Leaf extends Component {10 11 }12 13 interface Composite extends Component {14 15 void add(Component child);16 17 void remove(Component child);18 19 List<Component> getChildren();20 21 }
代码(杀毒举例)
1. AbstractFile.java
1 import java.util.ArrayList; 2 import java.util.List; 3 4 public interface AbstractFile { 5 6 void killVirus(); 7 8 } 9 10 class File implements AbstractFile {11 12 private String name;13 14 public File(String name) {15 this.name = name;16 }17 18 @Override19 public void killVirus() {20 System.out.println(name + " 文件杀毒!");21 }22 23 }24 25 class Folder implements AbstractFile {26 27 private String name;28 private List<AbstractFile> children = new ArrayList<>();29 30 public Folder(String name) {31 this.name = name;32 }33 34 public void add(AbstractFile child) {35 children.add(child);36 }37 38 public void remove(AbstractFile child) {39 children.remove(child);40 }41 42 @Override43 public void killVirus() {44 for (AbstractFile child : children) {45 child.killVirus();46 }47 System.out.println(name + " 文件夹杀毒!");48 }49 50 }
2. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 Folder myDocument = new Folder("我的文档"); 5 myDocument.add(new File("Client.java")); 6 myDocument.add(new File("index.php")); 7 myDocument.add(new File("老师.avi")); 8 Folder book = new Folder("图书"); 9 book.add(new File("设计模式.pdf"));10 book.add(new File("Hadoop权威指南.pdf"));11 myDocument.add(book);12 myDocument.killVirus();13 }14 15 }
应用场景
1. 操作系统的资源管理器。
2. GUI的容器层次图。
3. XML文件解析。
4. OA系统的组织结构处理。
5. JUnit单元测试框架:Test接口(抽象)、TestCase(叶子)、TestUnit(容器)。
装饰器模式(Decorator)
效果
1. 又称包装器模式(Wrapper)。
2. 动态的为一个对象增加新的功能。
3. 装饰器模式是一种用于代替继承的技术,无须通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。
4. 装饰器模式降低系统的耦合度,可以动态的增加或删除对象的职责,并使得需要装饰的具体构件类和具体装饰类可以独立变化,以便增加新的具体构件类和具体装饰类。
核心角色
1. 抽象构件角色(Component):具体构件角色和装饰角色有相同的接口,客户端能够以与具体构件角色相同的方式同装饰角色交互。
2. 具体构件角色(ConcreteComponent)。
3. 装饰角色(Decorator):持有一个抽象构件角色引用,接收所有客户端请求,并把这些请求转发给具体装饰角色。
4. 具体装饰角色(ConcreteDecorator):给构件增加新功能。
代码
1. ICar.java
1 public interface ICar { 2 3 void move(); 4 5 } 6 7 // 具体构建角色 8 class Car implements ICar { 9 10 @Override11 public void move() {12 System.out.println("陆地上跑!");13 }14 15 }16 17 // 装饰器角色18 abstract class SuperCar implements ICar {19 20 private ICar car;21 22 public SuperCar(ICar car) {23 this.car = car;24 }25 26 @Override27 public void move() {28 car.move();29 }30 31 }32 33 class FlyCar extends SuperCar {34 35 public FlyCar(ICar car) {36 super(car);37 }38 39 @Override40 public void move() {41 super.move();42 fly();43 }44 45 public void fly() {46 System.out.println("天上飞!");47 }48 49 }50 51 class WaterCar extends SuperCar {52 53 public WaterCar(ICar car) {54 super(car);55 }56 57 @Override58 public void move() {59 super.move();60 swim();61 }62 63 public void swim() {64 System.out.println("水上游!");65 }66 67 }68 69 class AICar extends SuperCar {70 71 public AICar(ICar car) {72 super(car);73 }74 75 @Override76 public void move() {77 super.move();78 autoMove();79 }80 81 public void autoMove() {82 System.out.println("自动跑!");83 }84 85 }
2. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 Car car = new Car(); 5 car.move(); 6 7 // 陆地上跑 + 天上飞 8 FlyCar flyCar = new FlyCar(car); 9 flyCar.move();10 11 // 陆地上跑 + 水上游12 WaterCar waterCar = new WaterCar(car);13 waterCar.move();14 15 // 陆地上跑 + 自动跑16 AICar aiCar = new AICar(car);17 aiCar.move();18 19 // 陆地上跑 + 天上飞 + 水上游20 WaterCar flyWaterCar = new WaterCar(flyCar);21 flyWaterCar.move();22 23 // 陆地上跑 + 天上飞 + 水上游 + 自动跑24 AICar aiFlyWaterCar = new AICar(flyWaterCar);25 aiFlyWaterCar.move();26 }27 28 }
应用场景
1. IO的InputStream、OutputStream、Reader、Writer的设计。
2. Servlet API的request对象的默认实现类HttpServletRequestWrapper。
外观模式(Facade)
效果
1. 为子系统提供统一的入口。封装子系统的复杂性,便于客户端调用。
2. 迪米特法则:一个软件实体应当尽可能少地与其他实体发生相互作用。
代码
1. Tea.java
1 public interface Tea {2 3 String getName();4 5 void drink();6 7 }
2. WaitressFacade.java
1 public class WaitressFacade { 2 3 public Tea makeTea(String teaName) { 4 Water water = new Water("农夫山泉", 100.0); 5 Tea tea = null; 6 switch (teaName) { 7 case "西湖龙井": 8 tea = new XiHuLongJing(); 9 break; 10 case "碧螺春": 11 tea = new BiLuoChun(); 12 break; 13 case "铁观音": 14 tea = new TieGuanYin(); 15 break; 16 default: 17 return null; 18 } 19 TeaSet teaSet = new TeaSet(); 20 teaSet.cleanTeaSet(water); 21 teaSet.addTea(tea); 22 teaSet.cleanTea(water); 23 teaSet.makeTea(water); 24 return tea; 25 } 26 27 } 28 29 class Water { 30 31 private String name; 32 33 private Double temperature; 34 35 public Water(String name, Double temperature) { 36 this.name = name; 37 this.temperature = temperature; 38 } 39 40 public String getName() { 41 return name; 42 } 43 44 public Double getTemperature() { 45 return temperature; 46 } 47 48 } 49 50 class TeaSet { 51 52 private Tea tea; 53 54 public void cleanTeaSet(Water water) { 55 System.out.println("使用" + water.getTemperature() + "°的" + water.getName() + "烫洗茶具!"); 56 } 57 58 public void addTea(Tea tea) { 59 System.out.println("投入" + tea.getName() + "!"); 60 this.tea = tea; 61 } 62 63 public void cleanTea(Water water) { 64 System.out.println("使用" + water.getTemperature() + "°的" + water.getName() + "洗茶!"); 65 } 66 67 public Tea makeTea(Water water) { 68 System.out.println("使用" + water.getTemperature() + "°的" + water.getName() + "泡茶!"); 69 return tea; 70 } 71 72 } 73 74 class XiHuLongJing implements Tea { 75 76 @Override 77 public String getName() { 78 return "西湖龙井"; 79 } 80 81 @Override 82 public void drink() { 83 System.out.println("品" + getName() + "!"); 84 } 85 86 } 87 88 class BiLuoChun implements Tea { 89 90 @Override 91 public String getName() { 92 return "洞庭碧螺春"; 93 } 94 95 @Override 96 public void drink() { 97 System.out.println("品" + getName() + "!"); 98 } 99 100 }101 102 class TieGuanYin implements Tea {103 104 @Override105 public String getName() {106 return "安溪铁观音";107 }108 109 @Override110 public void drink() {111 System.out.println("品" + getName() + "!");112 }113 114 }
3. Client.java
1 public class Client {2 3 public static void main(String[] args) {4 WaitressFacade waitressFacade = new WaitressFacade();5 Tea tea = waitressFacade.makeTea("铁观音");6 tea.drink();7 }8 9 }
应用场景
1. 频率很高,处处用到。
2. JDBC封装后的DbUtils类。
3. Hibernate提供的工具类。
4. Spring JDBC工具类等。
享元模式(FlyWeight)
效果
1. 享元模式以共享的方式高效地支持大量细粒度对象的重用。
a) 内存属于稀缺资源,不要随便浪费。如果有很多个完全相同或相似的对象,我们可以通过享元模式节省内存。
b) 用时间换取空间。
2. 享元对象能做到共享的关键是区分了内部状态和外部状态。
a) 内部状态:可以共享,不会随环境变化而变化。
b) 外部状态:不可以共享,会随环境变化而变化。
核心角色
1. 享元工厂类(FlyWeightFactory):创建并管理享元对象,享元池一般设计成键值对。
2. 抽象享元类(FlyWeight):通常是一个接口或抽象类,声明公共方法向外界提供对象的内部状态、设置外部状态。
3. 具体享元类(ConcreteFlyWeight):为内部状态提供成员变量进行存储。
4. 非共享享元类(UnsharedConcreteFlyWeight):不能被共享的子类可以设计为非共享享元类。
代码
1. ChessFlyWeight.java
1 // 抽象享元类2 public interface ChessFlyWeight {3 4 String getColor();5 6 void display(Position position);7 8 }
2. Position.java
1 // 非共享享元类 2 public class Position { 3 4 private int x; 5 6 private int y; 7 8 public Position(int x, int y) { 9 this.x = x;10 this.y = y;11 }12 13 public int getX() {14 return x;15 }16 17 public int getY() {18 return y;19 }20 21 }
3. ConcreteChess.java
1 // 具体享元类 2 public class ConcreteChess implements ChessFlyWeight { 3 4 private String color; 5 6 public ConcreteChess(String color) { 7 this.color = color; 8 } 9 10 @Override11 public String getColor() {12 return color;13 }14 15 @Override16 public void display(Position position) {17 System.out.println("显示:颜色" + color + ",位置(" + position.getX() + "," + position.getY() + ")!");18 }19 20 }
4. ChessFactory.java
1 import java.util.HashMap; 2 import java.util.Map; 3 4 // 享元工厂类 5 public class ChessFactory { 6 7 private static Map<String, ChessFlyWeight> chesses = new HashMap<>(); 8 9 public static ChessFlyWeight getChess(String color) {10 ChessFlyWeight chess = chesses.get(color);11 if (chess != null) {12 return chess;13 }14 chess = new ConcreteChess(color);15 chesses.put(color, chess);16 return chess;17 }18 19 }
5. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 ChessFlyWeight chess1 = ChessFactory.getChess("黑"); 5 ChessFlyWeight chess2 = ChessFactory.getChess("黑"); 6 System.out.println(chess1 == chess2); 7 8 chess1.display(new Position(10, 20)); 9 chess1.display(new Position(20, 10));10 }11 12 }
应用场景
1. 享元模式由于共享的特性,可以应用与任何“池”,比如线程池、数据库连接池。
2. String类的设计。
行为型模式
责任链模式(Chain of Resposibility)
效果
1. 将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求,如果能则处理,否则传递给链上的下一个对象。
2. 请假条审批过程:天数小于3天,主任审批;大于等于3天,小于10天,经理审批;大于等于10天,小于30天,总经理审批;大于等于30天,拒绝。
核心角色
1. 责任链既可以通过LinkedList实现,也可以通过ArrayList实现。
2. 可事先定义好责任链存储到配置文件或数据库。
代码
1. LeaveRequest.java
1 public class LeaveRequest { 2 3 private String name; 4 5 private int leaveDays; 6 7 private String reason; 8 9 public LeaveRequest(String name, int leaveDays, String reason) {10 this.name = name;11 this.leaveDays = leaveDays;12 this.reason = reason;13 }14 15 public String getName() {16 return name;17 }18 19 public int getLeaveDays() {20 return leaveDays;21 }22 23 public String getReason() {24 return reason;25 }26 27 }
2. Leave.java
1 public abstract class Leader { 2 3 protected String name; 4 5 protected Leader nextLeader; 6 7 public Leader(String name) { 8 this.name = name; 9 }10 11 public void setNextLeader(Leader nextLeader) {12 this.nextLeader = nextLeader;13 }14 15 public abstract void handleRequest(LeaveRequest leaveRequest);16 17 }18 19 class Director extends Leader {20 21 public Director(String name) {22 super(name);23 }24 25 @Override26 public void handleRequest(LeaveRequest leaveRequest) {27 if (leaveRequest.getLeaveDays() < 3) {28 System.out.println("主任" + name + "审批通过!");29 } else if (nextLeader != null) {30 nextLeader.handleRequest(leaveRequest);31 }32 }33 34 }35 36 class Manager extends Leader {37 38 public Manager(String name) {39 super(name);40 }41 42 @Override43 public void handleRequest(LeaveRequest leaveRequest) {44 if (leaveRequest.getLeaveDays() < 10) {45 System.out.println("经理" + name + "审批通过!");46 } else if (nextLeader != null) {47 nextLeader.handleRequest(leaveRequest);48 }49 }50 51 }52 53 class GeneralManager extends Leader {54 55 public GeneralManager(String name) {56 super(name);57 }58 59 @Override60 public void handleRequest(LeaveRequest leaveRequest) {61 if (leaveRequest.getLeaveDays() < 30) {62 System.out.println("总经理" + name + "审批通过!");63 } else {64 System.out.println("不通过!");65 }66 }67 68 }
3. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 Leader director = new Director("张三"); 5 Leader manager = new Manager("李四"); 6 Leader generalManager = new GeneralManager("王五"); 7 director.setNextLeader(manager); 8 manager.setNextLeader(generalManager); 9 10 LeaveRequest leaveRequest = new LeaveRequest("Tom", 5, "回英国老家。");11 director.handleRequest(leaveRequest);12 }13 14 }
应用场景
1. Java的异常捕获,try可对应多个catch,当第一个catch不匹配,则自动跳到第二个catch。
2. JavaScript的事件冒泡和捕获机制。
3. Servlet开发中,过滤器的链式处理。
迭代器模式(Iterator)
效果
1. 又称游标模式(Cursor)。
2. 提供一种可以遍历聚合对象的方式。
核心角色
1. 聚合对象(Aggregate):存储数据。
2. 迭代器(Iterator):遍历数据的算法,比如正序、倒序、随机等。
代码
1. Iterator.java
1 public interface Iterator {2 3 boolean hasNext();4 5 Object next();6 7 }
2. Aggregate.java
1 public interface Aggregate {2 3 void add(Object element);4 5 void remove(Object element);6 7 Iterator iterator();8 9 }
3. ConcreteAggregate.java
1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class ConcreteAggregate implements Aggregate { 5 6 private List<Object> list = new ArrayList<>(); 7 8 @Override 9 public void add(Object element) {10 list.add(element);11 }12 13 @Override14 public void remove(Object element) {15 list.remove(element);16 }17 18 @Override19 public Iterator iterator() {20 return new ConcreteAggregateIterator();21 }22 23 // 定义成内部类,可直接访问外部类的属性24 private class ConcreteAggregateIterator implements Iterator {25 26 private int cursor = -1;27 28 @Override29 public boolean hasNext() {30 return cursor < list.size() - 1;31 }32 33 @Override34 public Object next() {35 cursor++;36 return list.get(cursor);37 }38 39 }40 41 }
4. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 Aggregate aggregate = new ConcreteAggregate(); 5 aggregate.add("A"); 6 aggregate.add("B"); 7 aggregate.add("C"); 8 aggregate.add("D"); 9 aggregate.add("E");10 11 Iterator iterator = aggregate.iterator();12 while (iterator.hasNext()) {13 System.out.println(iterator.next());14 }15 }16 17 }
应用场景
JDK内置的迭代器。
中介者模式(Mediator)
效果
1. 如果一个系统中对象之间的联系呈现为网状结构,对象之间存在大量多对多关系,将导致关系及其复杂,这些对象称为“同事对象”。
2. 引入一个中介者对象,使各同事对象只跟中介者对象打交道,将复杂的网状结构解耦成星状结构。
3. 解耦多个同事对象之间的交互关系。每个对象都持有中介者对象的引用,只跟中介者对象打交道。我们通过中介者对象统一管理这些交互关系。
代码
1. 公司有总经理,各个部门有事情都通报给总经理,总经理再通知各个相关部门。总经理起到中介、协调作用。
2. Colleague.java
1 public interface Colleague {2 3 void selfAction();4 5 void outAction();6 7 }
3. Mediator.java
1 public interface Mediator {2 3 void register(String name, Colleague colleague);4 5 void command(String name);6 7 }
4. DevelopmentDepartment.java
1 public class DevelopmentDepartment implements Colleague { 2 3 private Mediator mediator; 4 5 public DevelopmentDepartment(Mediator mediator) { 6 this.mediator = mediator; 7 mediator.register("研发部", this); 8 } 9 10 @Override11 public void selfAction() {12 System.out.println("专心研发!");13 }14 15 @Override16 public void outAction() {17 System.out.println("研发部向总经理汇报:需要资金支持!");18 mediator.command("财务部");19 }20 21 }
5. MarcketDepartment.java
1 public class MarcketDepartment implements Colleague { 2 3 private Mediator mediator; 4 5 public MarcketDepartment(Mediator mediator) { 6 this.mediator = mediator; 7 mediator.register("市场部", this); 8 } 9 10 @Override11 public void selfAction() {12 System.out.println("专心接项目");13 }14 15 @Override16 public void outAction() {17 System.out.println("市场部向总经理汇报:需要资金支持!");18 }19 20 }
6. FinacialDepartment.java
1 public class FinacialDepartment implements Colleague { 2 3 private Mediator mediator; 4 5 public FinacialDepartment(Mediator mediator) { 6 this.mediator = mediator; 7 mediator.register("财务部", this); 8 } 9 10 @Override11 public void selfAction() {12 System.out.println("专心数钱!");13 }14 15 @Override16 public void outAction() {17 System.out.println("财务部向总经理汇报:钱太多,花不完!");18 mediator.command("市场部");19 }20 21 }
7. GeneralManager.java
1 import java.util.HashMap; 2 import java.util.Map; 3 4 public class GeneralManager implements Mediator { 5 6 private Map<String, Colleague> colleagues = new HashMap<>(); 7 8 @Override 9 public void register(String name, Colleague colleague) {10 colleagues.put(name, colleague);11 }12 13 @Override14 public void command(String name) {15 colleagues.get(name).outAction();16 }17 18 }
8. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 Mediator generalManager = new GeneralManager(); 5 Colleague developmentDepartment = new DevelopmentDepartment(generalManager); 6 Colleague marcketDepartment = new MarcketDepartment(generalManager); 7 Colleague finacialDepartment = new FinacialDepartment(generalManager); 8 9 developmentDepartment.selfAction();10 developmentDepartment.outAction();11 }12 13 }
应用场景
1. MVC模式的C是中介者对象,M和V都和他打交道。
2. GUI中,多个组件之间交互,可以引入一个中介者对象(整体窗口对象或DOM对象)。
3. java.lang.reflect.Method#invoke()。
命令模式(Command)
效果
1. 又称“动作模式(Action)、事务模式(Transaction)。
2. 将一个请求封装成一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。
核心角色
1. 抽象命令类(Command)。
2. 具体命令类(ConcreteCommand)。
3. 调用者/请求者(Invoker):请求的发送者,通过命令对象来执行请求。调用者并不需要在设计时确定接收者,而是在运行时,调用命令对象的execute(),间接调用接
收者的相关操作。
4. 接收者(Receiver):执行与请求相关的操作,具体实现对请求的业务处理。
代码
1. Command.java
1 public interface Command {2 3 // 实际中可设计多个方法4 void execute();5 6 }
2. ConcreteCommand.java
1 public class ConcreteCommand implements Command { 2 3 private Receiver receiver; 4 5 public ConcreteCommand(Receiver receiver) { 6 this.receiver = receiver; 7 } 8 9 @Override10 public void execute() {11 // 可在执行前后做其他操作,比如记录日志12 receiver.action();13 }14 15 }
3. Invoker.java
1 public class Invoker { 2 3 // 也可以是多条命令,类似数据库事务中的多条命令 4 private Command command; 5 6 public Invoker(Command command) { 7 this.command = command; 8 } 9 10 public void call() {11 command.execute();12 }13 14 }
4. Receiver.java
1 public class Receiver {2 3 public void action() {4 System.out.println("Receiver.action()");5 }6 7 }
5. Client.java
1 public class Client {2 3 public static void main(String[] args) {4 Command command = new ConcreteCommand(new Receiver());5 Invoker invoker = new Invoker(command);6 invoker.call();7 }8 9 }
应用场景
数据库事务机制的底层实现。
解释器模式(Interpreter)
效果
1. 不常用的设计模式。
2. 用于描述如何构成一个简单的语言解释器,主要用于使用面向对象语言开发的编译器和解释器设计。
3. 尽量不要使用解释器模式,后期维护非常麻烦。在项目中,可以使用JRuby、Groovy、Java的JavaScript引擎来代替解释器,弥补Java语言不足。
应用场景
1. EL表达式的处理。
2. 正则表达式解释器。
3. SQL语法解释器。
4. 数学表达式解析器,如工具包Math Expression String Parser、Expression4J。
访问者模式(Visitor)
效果
1. 不常用的设计模式。
2. 对于存储在一个集合中的对象,他们可能具有不同的类型(即使有一个公共的接口),对于该集合中的对象,可以接收一类称为访问者的对象来访问,不同的访问者其访问方式也有所不同。
3. 表示一个作用于某对象结构中各元素的操作,使我们可以不在改变元素类的前提下定义作用于这些元素的新操作。
应用场景
1. XML文档解析器设计。
2. 编译器的设计。
3. 复杂集合对象的处理。
策略模式(Strategy)
效果
1. 策略模式对应于解决某一个问题的一个算法族,允许客户端从该算法族中任选一个算法解决问题,同时可以方便更换算法或添加新的算法。
2. 本质:分离算法,选择实现。
代码
1. 某个市场人员接到单后的报销策略(CRM系统的常见问题)。报价策略很复杂:
a) 普通客户小批量报价;
b) 普通客户大批量报价;
c) 老客户小批量报价;
d) 老客户大批量报价。
2. Strategy.java
1 public interface Strategy {2 3 double getPrice(double standardPrice);4 5 }
3. Context.java
1 // 负责与具体的策略类交互,将客户端与算法分离 2 public class Context { 3 4 private Strategy strategy; 5 6 public Context(Strategy strategy) { 7 this.strategy = strategy; 8 } 9 10 public void printPrice(double standardPrice) {11 System.out.println(strategy.getPrice(standardPrice));12 }13 14 }
4. NewCustomerFewStrategy.java
1 public class NewCustomerFewStrategy implements Strategy {2 3 @Override4 public double getPrice(double standardPrice) {5 System.out.println("不打折!");6 return standardPrice;7 }8 9 }
5. NewCustomerManyStrategy.java
1 public class NewCustomerManyStrategy implements Strategy {2 3 @Override4 public double getPrice(double standardPrice) {5 System.out.println("打九折!");6 return standardPrice * 0.9;7 }8 9 }
6. OldCustomerFewStrategy.java
1 public class OldCustomerFewStrategy implements Strategy {2 3 @Override4 public double getPrice(double standardPrice) {5 System.out.println("打八五折!");6 return standardPrice * 0.85;7 }8 9 }
7. OldCustomerManyStrategy.java
1 public class OldCustomerManyStrategy implements Strategy {2 3 @Override4 public double getPrice(double standardPrice) {5 System.out.println("打八折!");6 return standardPrice * 0.8;7 }8 9 }
8. Client.java
1 public class Client {2 3 public static void main(String[] args) {4 Strategy strategy = new OldCustomerManyStrategy(); // 可通过配置生成5 Context context = new Context(strategy);6 context.printPrice(998);7 }8 9 }
应用场景
1. Java的GUI编程,布局管理。
2. Spring框架的Resource接口,资源访问策略。
3. javax.servlet.http.HttpServlet#service()。
模板方法模式(Template Method)
效果
1. 常用的模式。
2. 模板方法定义一个操作的算法框架,将某些步骤延迟到子类中实现。这样,新的子类可以在不改变算法结构的前提下,重新定义该算法的某些特定步骤。
代码
1. BankTemplateMethod.java
1 public abstract class BankTemplateMethod { 2 3 protected void takeNumber() { 4 System.out.println("取号!"); 5 } 6 7 protected void waitInLine() { 8 System.out.println("排队!"); 9 }10 11 // 钩子方法/回调方法:办理具体业务12 protected abstract void transaction();13 14 protected void evaluate() {15 System.out.println("评分!");16 }17 18 // 模板方法19 public final void process() {20 takeNumber();21 waitInLine();22 transaction();23 evaluate();24 }25 26 }
2. DrawMoney.java
1 public class DrawMoney extends BankTemplateMethod {2 3 @Override4 protected void transaction() {5 System.out.println("取款!");6 }7 8 }
3. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 BankTemplateMethod drawMoney = new DrawMoney(); 5 drawMoney.process(); 6 7 // 匿名内部类实现 8 new BankTemplateMethod() { 9 10 @Override11 protected void transaction() {12 System.out.println("存款!");13 }14 15 }.process();;16 }17 18 }
应用场景
1. 各框架、类库都有模板方法。
2. 数据库访问的封装。
3. JUnit单元测试。
4. Servlet的doGet()和doPost()方法调用。
5. Spring的JDBCTemplate、HibernateTemplate。
状态模式(State)
效果
1. 用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。
2. 酒店系统中,房间的状态变化。
核心角色
1. 上下文类(Context):环境类中维护一个State对象,定义了当前的状态。
2. 抽象状态类(State)。
3. 具体状态类(ConcreteState):每一个类封装了一个状态对应的行为。
代码
1. State.java
1 public interface State {2 3 void handle();4 5 }
2. RoomContext.java
1 public class RoomContext { 2 3 private State state; 4 5 public State getState() { 6 return state; 7 } 8 9 public void setState(State state) {10 this.state = state;11 state.handle();12 }13 14 }
3. FreeState.java
1 public class FreeState implements State {2 3 @Override4 public void handle() {5 System.out.println("退出房间!");6 }7 8 }
4. BookedState.java
1 public class BookedState implements State {2 3 @Override4 public void handle() {5 System.out.println("预定房间!");6 }7 8 }
5. CheckedInState.java
1 public class CheckedInState implements State {2 3 @Override4 public void handle() {5 System.out.println("入住房间!");6 }7 8 }
6. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 RoomContext context = new RoomContext(); 5 context.setState(new FreeState()); 6 context.setState(new BookedState()); 7 context.setState(new CheckedInState()); 8 } 9 10 }
应用场景
1. 银行系统的账号状态管理。
2. OA系统的公文状态管理。
3. 酒店系统的房间状态管理。
4. 线程对象各状态之间的切换。
观察者模式(Observer)
效果
1. 观察者模式用于1:N的消息通知。
2. 当目标对象(Subject或Observable)的状态变化(消息发布)时,他及时告知一系列观察者对象(Observer),令他们做出相应(消息订阅)。
3. 通知观察者的方式:
a) 推:每次都会把消息以广播方式发送给所有观察者,所有观察者只能被动接收。
b) 拉:观察者只要知道有变化即可,什么时候获取消息、获取什么内容,都由观察者自主决定。
代码
1. Subject.java
1 import java.util.ArrayList; 2 import java.util.List; 3 4 public abstract class Subject { 5 6 private List<Observer> observers = new ArrayList<>(); 7 8 public void subscribe(Observer observer) { 9 observers.add(observer);10 }11 12 public void unsubscribe(Observer observer) {13 observers.remove(observer);14 }15 16 public void notifyAllObservers() {17 for (Observer observer : observers) {18 observer.update(this);19 }20 }21 22 }
2. ConcreteSubject.java
1 public class ConcreteSubject extends Subject { 2 3 private int state; 4 5 public int getState() { 6 return state; 7 } 8 9 public void setState(int state) {10 this.state = state;11 notifyAllObservers();12 }13 14 }
3. Observer.java
1 public interface Observer {2 3 void update(Subject subject);4 5 }
4. ConcreteObserver.java
1 public class ConcreteObserver implements Observer { 2 3 private String name; 4 5 public ConcreteObserver(String name) { 6 this.name = name; 7 } 8 9 @Override10 public void update(Subject subject) {11 System.out.println(name + "收到消息:state=" + ((ConcreteSubject) subject).getState());12 }13 14 }
5. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 ConcreteSubject subject = new ConcreteSubject(); 5 Observer observer1 = new ConcreteObserver("张三"); 6 Observer observer2 = new ConcreteObserver("李四"); 7 Observer observer3 = new ConcreteObserver("王五"); 8 subject.subscribe(observer1); 9 subject.subscribe(observer2);10 subject.subscribe(observer3);11 12 subject.setState(1);13 subject.setState(2);14 }15 16 }
代码(基于JDK)
1. ConcreteSubject.java
1 import java.util.Observable; 2 3 public class ConcreteSubject extends Observable { 4 5 private int state; 6 7 public int getState() { 8 return state; 9 }10 11 public void setState(int state) {12 this.state = state;13 // 目标对象已变化14 setChanged();15 // 通知观察者16 notifyObservers(state);17 }18 19 }
2. ConcreteObserver.java
1 import java.util.Observable; 2 import java.util.Observer; 3 4 public class ConcreteObserver implements Observer { 5 6 private String name; 7 8 public ConcreteObserver(String name) { 9 this.name = name;10 }11 12 @Override13 public void update(Observable observable, Object arg) {14 ConcreteSubject subject = (ConcreteSubject) observable;15 System.out.println(name + "收到消息:" + arg);16 System.out.println(name + "获取最新状态:" + subject.getState());17 }18 19 }
3. Client.java
1 import java.util.Observer; 2 3 public class Client { 4 5 public static void main(String[] args) { 6 ConcreteSubject subject = new ConcreteSubject(); 7 Observer observer1 = new ConcreteObserver("张三"); 8 Observer observer2 = new ConcreteObserver("李四"); 9 Observer observer3 = new ConcreteObserver("王五");10 subject.addObserver(observer1);11 subject.addObserver(observer2);12 subject.addObserver(observer3);13 14 subject.setState(1);15 subject.setState(2);16 }17 18 }
应用场景
1. 聊天室,服务器转发给所有客户端。
2. 网络游戏多人联机对战,服务器将客户端的状态进行分发。
3. 邮件订阅。
4. Servlet编程,监听器的实现。
5. Android,广播机制。
6. 京东商城,群发某商品打折信息。
备忘录模式(Memento)
效果
保存某个对象内部状态的拷贝,以后可以将该对象恢复到原先状态。
核心角色
1. 源发器类(Originator):负责创建一个备忘录类,用以记录当前内部状态,并可使用备忘录恢复内部状态。
2. 备忘录类(Memento):负责存储源发器类的内部状态,并可防止源发器类以外的其他对象访问备忘录类。
3. 负责人类(CareTaker):负责保存好备忘录,备忘点较多时,可用List或Stack存储。也可以持久化。
代码
1. Employee.java
1 // 源发器类 2 public class Employee { 3 4 private String name; 5 6 private int age; 7 8 private double salary; 9 10 public Employee(String name, int age, double salary) {11 this.name = name;12 this.age = age;13 this.salary = salary;14 }15 16 // 备忘17 public EmployeeMemento memento() {18 return new EmployeeMemento(this);19 }20 21 // 恢复22 public void recover(EmployeeMemento employeeMemento) {23 this.name = employeeMemento.getName();24 this.age = employeeMemento.getAge();25 this.salary = employeeMemento.getSalary();26 }27 28 public String getName() {29 return name;30 }31 32 public void setName(String name) {33 this.name = name;34 }35 36 public int getAge() {37 return age;38 }39 40 public void setAge(int age) {41 this.age = age;42 }43 44 public double getSalary() {45 return salary;46 }47 48 public void setSalary(double salary) {49 this.salary = salary;50 }51 52 @Override53 public String toString() {54 return "name=" + name + ",age=" + age + ",salary=" + salary;55 }56 57 }
2. EmployeeMemento.java
1 public class EmployeeMemento { 2 3 private String name; 4 5 private int age; 6 7 private double salary; 8 9 public EmployeeMemento(Employee employee) {10 this.name = employee.getName();11 this.age = employee.getAge();12 this.salary = employee.getSalary();13 }14 15 public String getName() {16 return name;17 }18 19 public int getAge() {20 return age;21 }22 23 public double getSalary() {24 return salary;25 }26 27 }
3. EmployeeCareTaker.java
1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class EmployeeCareTaker { 5 6 private List<EmployeeMemento> mementoes = new ArrayList<>(); 7 8 public void addMemento(EmployeeMemento mementoe) { 9 mementoes.add(mementoe);10 }11 12 public EmployeeMemento getMemento(int index) {13 return mementoes.get(index);14 }15 16 public EmployeeMemento getLastMemento() {17 return getMemento(mementoes.size() - 1);18 }19 20 }
4. Client.java
1 public class Client { 2 3 public static void main(String[] args) { 4 EmployeeCareTaker careTaker = new EmployeeCareTaker(); 5 6 Employee employee = new Employee("张三", 18, 1000); 7 System.out.println(employee); 8 9 careTaker.addMemento(employee.memento());10 employee.setAge(20);11 employee.setSalary(3000);12 System.out.println(employee);13 careTaker.addMemento(employee.memento());14 15 employee.setAge(21);16 System.out.println(employee);17 18 employee.recover(careTaker.getLastMemento());19 System.out.println(employee);20 }21 22 }
应用场景
1. 棋类游戏的悔棋。
2. 编辑软件的撤销操作。
3. 数据库的事务回滚操作。
4. Photoshop的历史版本记录。
作者:netoxi
出处:http://www.cnblogs.com/netoxi
本文版权归作者和博客园共有,欢迎转载,未经同意须保留此段声明,且在文章页面明显位置给出原文连接。欢迎指正与交流。
设计模式笔记——GoF设计模式汇总