51 KiB
设计模式
设计模式是对许多业务和算法的抽象,因此学习起来具有一定的难度。短时间内掌握是不可能的,需要通过不断的实践和理解来积累经验。对于已经在职场上工作,但后期才开始学习设计模式的人来说,可能会面临更多的挑战。
在学习设计模式时,很多概念趋于理论化,且种类繁多(设计模式总共有23种),如果没有进行系统的梳理,可能很难直接应用到实际场景中。
设计模式中的抽象类通常是接口或抽象类,这些类的实现会根据具体的业务需求进行调整,因而不一定是唯一的实现方式。
在我学习过程中,我试图将所学的内容总结下来,但由于篇幅有限,无法一一列举所有场景,只能举出一些常见的例子。
工厂模式---创建型
工厂模式(Factory Pattern)介绍
工厂模式属于创建型设计模式,主要用于通过定义一个接口来创建对象,但让子类决定实例化哪一个类。通过这种方式,工厂模式将对象的创建与使用分离,从而解耦了客户端与具体类的依赖关系。
工厂模式的核心思想是:让子类决定具体要创建哪一个产品,而不是直接在客户端代码中硬编码要使用哪个类。
工厂模式的主要角色
- 产品接口(Product):通常是一个接口或者抽象类,定义了具体产品的公共方法。
- 具体产品(ConcreteProduct):实现了产品接口的具体类,代表不同的产品。
- 工厂接口(Creator):通常是一个抽象类或接口,定义了一个工厂方法用于创建产品。
- 具体工厂(ConcreteCreator):实现了工厂接口的具体类,负责创建具体的产品对象。
工厂模式的类型
- 简单工厂模式(Simple Factory):通过工厂类中的一个方法,根据传入的参数决定返回哪种具体的产品对象。
- 工厂方法模式(Factory Method):通过一个工厂接口或者抽象类来定义创建产品的工厂方法,让子类决定创建哪个具体产品。
- 抽象工厂模式(Abstract Factory):提供一个创建一系列相关或相互依赖对象的接口,而无需指定具体类。
简单工厂模式示例(Java)
// 产品接口
public interface Product {
void create();
}
// 具体产品A
public class ProductA implements Product {
@Override
public void create() {
System.out.println("Product A created.");
}
}
// 具体产品B
public class ProductB implements Product {
@Override
public void create() {
System.out.println("Product B created.");
}
}
// 工厂类
public class ProductFactory {
// 简单工厂方法,根据输入参数创建不同的产品
public static Product createProduct(String productType) {
if ("A".equals(productType)) {
return new ProductA();
} else if ("B".equals(productType)) {
return new ProductB();
}
throw new IllegalArgumentException("Unknown product type");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Product productA = ProductFactory.createProduct("A");
productA.create();
Product productB = ProductFactory.createProduct("B");
productB.create();
}
}
优点
- 降低耦合度:工厂模式将对象的创建过程与使用过程分开,客户端不需要了解具体的创建过程,从而降低了耦合度。
- 易于扩展:可以通过新增具体产品类和工厂方法来扩展系统,不需要修改现有代码,符合开闭原则(OCP)。
- 提高代码的可维护性:当需要修改创建产品的逻辑时,只需修改工厂类,不影响客户端代码。
缺点
- 增加类的数量:引入了工厂类、产品接口和多个具体产品类,可能导致类的数量增加,系统变得复杂。
- 难以理解和维护:对于一些简单的应用程序,使用工厂模式可能会使得设计过于复杂,反而增加了理解和维护的难度。
单例模式---创建型
懒汉模式
双重检查锁定(DCL)
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
// 构造函数私有化
}
public static Singleton getInstance() {
if (instance == null) { // 第一次检查
synchronized (Singleton.class) {
if (instance == null) { // 第二次检查
instance = new Singleton();
}
}
}
return instance;
}
}
静态内部类方式
利用 静态内部类(饿汉式)的特性来实现懒汉模式,并且可以保证线程安全。这种方式只有在调用 getInstance()
时才会加载内部类,从而实现懒加载。
public class Singleton {
private Singleton() {
// 构造函数私有化
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
适用场景
-
如果单例对象比较重,且只在程序中某些特定情况下才使用,懒汉模式可以带来性能优势。
-
在低并发环境或单线程环境下,懒汉模式使用较为简单,不会有多线程安全问题。
-
对于高并发且需要频繁访问单例的场景,推荐使用静态内部类或饿汉模式来避免懒汉模式可能带来的性能问题。
-
优点:
- 延迟加载,节省资源。
- 内存优化,只有在需要时才实例化。
- 减少不必要的初始化开销。
-
缺点:
- 传统懒汉模式线程不安全(多个线程可能会创建多个实例)。
- 使用同步机制会有性能开销,特别是在多线程环境下。
- 代码复杂性较高,容易引入错误。
- 不适合高并发场景,特别是频繁访问时会影响性能。
饿汉模式
饿汉模式(Eager Initialization)是单例模式的一种实现方式,在该方式中,单例实例在类加载时就已经创建完成,而不是在首次使用时才创建。换句话说,饿汉模式 的单例实例在类被加载时就会立即初始化,确保了单例模式的唯一性。
public class Singleton {
// 在类加载时就初始化单例对象
private static final Singleton INSTANCE = new Singleton();
// 私有构造函数,防止外部通过 new 创建实例
private Singleton() {
}
// 提供全局访问点
public static Singleton getInstance() {
return INSTANCE;
}
}
适用场景
-
简单应用:适合没有延迟初始化需求的小型应用,或者单例对象的创建非常轻量,不会影响系统性能的场景。
-
实例化不耗费太多资源:如果单例对象的初始化过程非常轻量级且无须延迟初始化,可以使用饿汉模式。
-
类加载顺序固定:如果不在乎单例对象在启动时是否初始化,且单例对象的初始化过程没有严重性能损失,可以选择饿汉模式。
-
优点:简单、线程安全、性能高(没有锁机制)、实现方便。
-
缺点:不支持延迟加载、可能会浪费资源(如果单例对象不常用时)。
饿汉模式是单例模式中最简单的实现方式,适用于大多数情况下单例对象的创建开销较小,且不需要延迟初始化的场景。如果单例对象的创建非常轻量且不依赖于后期加载时的资源,饿汉模式是一个不错的选择。
枚举类型实现
枚举类型实现单例模式(Enum Singleton)是实现单例模式的另一种方式,优点是更加简洁、可靠,并且避免了许多常见的单例实现方式(如懒汉模式和饿汉模式)可能出现的问题。使用枚举类型的单例实现方式自 Java 5 引入以来,已经成为了最推荐的单例模式实现方式之一。
当你不需要懒加载或延迟初始化时,使用枚举实现单例模式是最理想的选择。
public enum Singleton {
// 唯一实例
INSTANCE;
// 可以添加其他的方法
public void someMethod() {
System.out.println("This is a singleton instance method.");
}
}
使用示例
public class Main {
public static void main(String[] args) {
// 获取单例对象
Singleton singleton = Singleton.INSTANCE;
// 调用单例方法
singleton.someMethod();
}
}
原型模式---创建型
需要三个角色:抽象原型类(Abstract Prototype)、具体原型类(Concrete Prototype)、访问类(Client)
简单示例
提示:需要做深克隆,当类中还存在另一个类时
错误示例代码
当我们对school对象进行设置时,对resume1
进行设置结果resume
也发生了改变。需要修改Resume
类中的clone
方法
public class Prototype {
public static void main(String[] args) {
Resume resume = new Resume();
resume.name = "Bunny";
resume.position = "架构师";
resume.salary = 15000;
School school = new School();
school.schoolName = "江南大学";
school.time = "2025年2月2日21:38:07";
resume.school = school;
System.out.println(resume);
Resume resume1 = resume.clone();
resume1.salary = 19000;
resume1.school.schoolName = "清华大学";
System.out.println(resume1);
Resume resume2 = resume.clone();
resume2.salary = 20000;
System.out.println(resume2);
System.out.println(resume1 == resume2);// false
System.out.println(resume1.school == resume2.school);// true
}
@Data
static class Resume implements Cloneable {
private String name;
private String position;
private Integer salary;
private School school;
@Override
public Resume clone() {
try {
return (Resume) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
@Data
static class School implements Cloneable {
private String schoolName;
private String time;
@Override
public School clone() {
try {
return (School) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
}
运行结果:
Prototype.Resume(name=Bunny, position=架构师, salary=15000, school=Prototype.School(schoolName=江南大学, time=2025年2月2日21:38:07))
Prototype.Resume(name=Bunny, position=架构师, salary=19000, school=Prototype.School(schoolName=清华大学, time=2025年2月2日21:38:07))
Prototype.Resume(name=Bunny, position=架构师, salary=20000, school=Prototype.School(schoolName=清华大学, time=2025年2月2日21:38:07))
false
true
正确示例代码
修改conle
@Data
static class Resume implements Cloneable {
private String name;
private String position;
private Integer salary;
private School school;
@Override
public Resume clone() {
Resume resume = null;
try {
resume = (Resume) super.clone();
if (school != null) {
resume.school = school.clone();
}
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
return resume;
}
}
示例
public class Prototype {
public static void main(String[] args) {
Resume resume = new Resume();
resume.name = "Bunny";
resume.position = "架构师";
resume.salary = 15000;
School school = new School();
school.schoolName = "江南大学";
school.time = "2025年2月2日21:38:07";
resume.school = school;
System.out.println(resume);
Resume resume1 = resume.clone();
resume1.salary = 19000;
resume1.school.schoolName = "清华大学";
System.out.println(resume1);
Resume resume2 = resume.clone();
resume2.salary = 20000;
System.out.println(resume2);
System.out.println(resume1 == resume2);// false
System.out.println(resume1.school == resume2.school);// false
}
@Data
static class Resume implements Cloneable {
private String name;
private String position;
private Integer salary;
private School school;
@Override
public Resume clone() {
Resume resume = null;
try {
resume = (Resume) super.clone();
if (school != null) {
resume.school = school.clone();
}
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
return resume;
}
}
@Data
static class School implements Cloneable {
private String schoolName;
private String time;
@Override
public School clone() {
try {
return (School) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
}
运行结果:
Prototype.Resume(name=Bunny, position=架构师, salary=15000, school=Prototype.School(schoolName=江南大学, time=2025年2月2日21:38:07))
Prototype.Resume(name=Bunny, position=架构师, salary=19000, school=Prototype.School(schoolName=清华大学, time=2025年2月2日21:38:07))
Prototype.Resume(name=Bunny, position=架构师, salary=20000, school=Prototype.School(schoolName=江南大学, time=2025年2月2日21:38:07))
false
false
建造者模式
简单示例
比如我们要构建一个复杂的 Computer
(计算机)对象。我们可以定义一个 ComputerBuilder
,它将按顺序设置计算机的 CPU、内存、硬盘等组件,最后得到一个完整的 Computer
对象。
代码示例
public class CommandDemo {
public static void main(String[] args) {
ConcreteLowComputerBuilder concreteLowComputerBuilder = new ConcreteLowComputerBuilder();
Director director = new Director(concreteLowComputerBuilder);
director.constructComputer();
System.out.println(concreteLowComputerBuilder.getComputer());
System.out.println("\n-----------------分割线-----------------\n");
ConcreteHighComputerBuilder concreteHighComputerBuilder = new ConcreteHighComputerBuilder();
director = new Director(concreteHighComputerBuilder);
director.constructComputer();
System.out.println(concreteHighComputerBuilder.getComputer());
}
// 构建产品接口
interface ComputerBuilder {
/**
* 构建 CPU 方法
*/
void buildCPU();
/**
* 构建 RAM 方法
*/
void buildRAM();
/**
* 构建 磁盘 方法
*/
void buildHardDrive();
/**
* 返回产品
*
* @return Computer
*/
Computer getComputer();
}
// 产品类
@Data
static class Computer {
private String CPU;
private String RAM;
private String hardDrive;
}
// 构建低端产品
static class ConcreteLowComputerBuilder implements ComputerBuilder {
private final Computer computer = new Computer();
/**
* 构建 CPU 方法
*/
@Override
public void buildCPU() {
computer.setCPU("Low CPU");
}
/**
* 构建 RAM 方法
*/
@Override
public void buildRAM() {
computer.setRAM("Low RAM");
}
/**
* 构建 磁盘 方法
*/
@Override
public void buildHardDrive() {
computer.setHardDrive("Low Driver");
}
/**
* 返回产品
*
* @return Computer
*/
@Override
public Computer getComputer() {
return computer;
}
}
// 构建高端产品
static class ConcreteHighComputerBuilder implements ComputerBuilder {
private final Computer computer = new Computer();
/**
* 构建 CPU 方法
*/
@Override
public void buildCPU() {
computer.setCPU("High CPU");
}
/**
* 构建 RAM 方法
*/
@Override
public void buildRAM() {
computer.setRAM("High RAM");
}
/**
* 构建 磁盘 方法
*/
@Override
public void buildHardDrive() {
computer.setHardDrive("High Driver");
}
/**
* 返回产品
*
* @return Computer
*/
@Override
public Computer getComputer() {
return computer;
}
}
// 构建者
public static class Director {
private final ComputerBuilder builder;
public Director(ComputerBuilder builder) {
this.builder = builder;
}
public void constructComputer() {
builder.buildCPU();
builder.buildRAM();
builder.buildHardDrive();
}
}
}
运行结果:
CommandDemo.Computer(CPU=Low CPU, RAM=Low RAM, hardDrive=Low Driver)
-----------------分割线-----------------
CommandDemo.Computer(CPU=High CPU, RAM=High RAM, hardDrive=High Driver)
装饰者模式---结构型
一共有四个角色。
- 抽象组件:一般是最原始、最基础的对象。
- 具体组件:一般是最原始最基础的实现对象,可以有多个(只是数量不多),可以大致看下
InputStream
UML结构图。 - 装饰角色:继承或者实现抽象组件这是最关键的地方。
- 具体装饰角色:可以有多个实现或者继承装饰角色。
简单示例
需要做一个抽象的相机功能,相机包含拍照功能(这是肯定的),之后随着业务需求要求相机有美颜功能,在这之后还要有滤镜功能,客户还需要延迟摄影功能。
代码实现
-
需要定义根组件(Component)
-
制作最原始的拍照功能,实现根组件
-
制作延迟摄影,实现根组件
-
作为相机之外的功能(美颜),需要定义装饰角色方便为以后的组件进行扩展
-
继承或者实现(装饰者角色),完成美颜
-
继承或者实现(装饰者角色),完成滤镜
public class CameraDemo {
public static void main(String[] args) {
TakePhotoCamera takePhotoCamera = new TakePhotoCamera();
takePhotoCamera.operation();
System.out.println("\n-----------------分割线-----------------\n");
BeautyCamera beautyCamera = new BeautyCamera(takePhotoCamera);
beautyCamera.operation();
System.out.println("\n-----------------分割线-----------------\n");
FilterCamera filterCamera = new FilterCamera(beautyCamera);
filterCamera.operation();
System.out.println("\n-----------------分割线-----------------\n");
TimerCamera timerCamera = new TimerCamera();
timerCamera.setTime(2);
timerCamera.operation();
filterCamera = new FilterCamera(beautyCamera);
filterCamera.operation();
}
// 相机功能
interface Camera {
/**
* 相机操作
*/
void operation();
}
// 相机装饰者角色
static abstract class CameraDecorator implements Camera {
Camera camera;
public CameraDecorator(Camera camera) {
this.camera = camera;
}
}
// 相机拍照
static class TakePhotoCamera implements Camera {
/**
* 相机操作
*/
@Override
public void operation() {
System.out.println("相机拍照。。。");
}
}
// 相机功能
static class BeautyCamera extends CameraDecorator {
public BeautyCamera(Camera camera) {
super(camera);
}
/**
* 相机操作
*/
@Override
public void operation() {
camera.operation();
System.out.println("美颜功能。。。");
}
}
// 滤镜效果
static class FilterCamera extends CameraDecorator {
public FilterCamera(Camera camera) {
super(camera);
}
/**
* 相机操作
*/
@Override
public void operation() {
camera.operation();
System.out.println("滤镜效果。。。");
}
}
// 实现相机延迟功能
@Setter
static class TimerCamera implements Camera {
// 延迟时间
private Integer time = 0;
/**
* 相机操作
*/
@Override
public void operation() {
System.out.println("开始拍照,延迟时间:" + time + "s");
try {
Thread.sleep(time * 1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
运行结果:
相机拍照。。。
-----------------分割线-----------------
相机拍照。。。
美颜功能。。。
-----------------分割线-----------------
相机拍照。。。
美颜功能。。。
滤镜效果。。。
-----------------分割线-----------------
开始拍照,延迟时间:2s
相机拍照。。。
美颜功能。。。
滤镜效果。。。
外观模式---结构型
有点类似网址导航的思想,比如有很多零散的东西(网址)但是每次我们想用的时候需要寻找这些网址,如果有个网址大全讲这些网址封装我们寻找会方便很多。
再或者,我们每天看天气,需要打开手机点开天气应用、熄屏;如果我们将这些东西封装成单独的指令会简化我们平时的行为,比如写个脚本执行上面的事情。
主要角色:门面角色(Facade)、子系统角色(Sub System)、客户角色(Client)。
简单实现
示例代码
public class Facade {
public static void main(String[] args) {
DeviceFacade deviceFacade = new DeviceFacade();
// 查看
deviceFacade.on();
// 看完关闭
deviceFacade.off();
}
// 子系统-手机
static class SubSystemIPhone {
public void on() {
System.out.println("打开手机。。。");
}
public void off() {
System.out.println("关闭手机。。。");
}
}
// 子系统-天气
static class SubSystemWeather {
public void on() {
System.out.println("打开天气。。。");
}
public void off() {
System.out.println("关闭天气。。。");
}
}
// 门面
static class DeviceFacade {
// 也可以作为参数传递,如果没有别的实现类,直接在内部初始化会使使用者更简单
SubSystemIPhone subSystemIPhone = new SubSystemIPhone();
SubSystemWeather subSystemWeather = new SubSystemWeather();
public void on() {
subSystemIPhone.on();
subSystemWeather.on();
}
public void off() {
subSystemWeather.off();
subSystemIPhone.off();
}
}
}
运行结果:
打开手机。。。
打开天气。。。
关闭天气。。。
关闭手机。。。
适配器模式---结构型
需要角色:抽象适配者角色(Abstract Adapter)、适配者角色(Adapter)、目标角色(Target)
在生活中,有时需要将380V三相电转成220V,这时候需要变压器,当然也有三相电转两相电接法,我们可以使用代码模拟这个操作 。
类适配器
示例代码
public class Adapter1 {
public static void main(String[] args) {
PowerAdapter powerAdapter = new PowerAdapter();
Integer integer = powerAdapter.output220V();
System.out.println("----------------");
PowerAdapter powerAdapter1 = new PowerAdapter();
powerAdapter1.output220V();
Integer i = powerAdapter1.output380V();
}
// 电压输出
interface PowerTarget {
/**
* 输出电压220V
*
* @return 输出电压
*/
Integer output220V();
}
static class PowerAdapter extends Power implements PowerTarget {
/**
* 输出电压220V
*
* @return 输出电压
*/
@Override
public Integer output220V() {
Integer output = super.getOutput();
System.out.println("变压器交流" + output + "v转220v三相电变两项电。。。");
double adapter = new Random().nextDouble(1.64, 1.72);
Integer newOutput = (int) (output / adapter);
System.out.println("变压器转换完成:电压输出为:" + newOutput);
return newOutput;
}
}
@Data
static class Power {
private Integer output = 380;
public Integer output380V() {
System.out.println("输出电压:" + output);
return output;
}
}
}
运行结果:
变压器交流380v转220v三相电变两项电。。。
变压器转换完成:电压输出为:224
----------------
变压器交流380v转220v三相电变两项电。。。
变压器转换完成:电压输出为:224
输出电压:380
对象适配器
示例代码
public class Adapter2 {
public static void main(String[] args) {
Power power = new Power();
PowerAdapter powerAdapter = new PowerAdapter(power);
Integer integer = powerAdapter.output220V();
}
// 电压输出
interface PowerTarget {
/**
* 输出电压220V
*
* @return 输出电压
*/
Integer output220V();
}
@Setter
@Getter
static class PowerAdapter implements PowerTarget {
private final Power power;
public PowerAdapter(Power power) {
this.power = power;
}
/**
* 输出电压220V
*
* @return 输出电压
*/
@Override
public Integer output220V() {
Integer output = power.getOutput();
System.out.println("变压器交流" + output + "v转220v三相电变两项电。。。");
double adapter = new Random().nextDouble(1.64, 1.72);
Integer newOutput = (int) (output / adapter);
System.out.println("变压器转换完成:电压输出为:" + newOutput);
return newOutput;
}
}
@Data
static class Power {
private Integer output = 380;
public Integer output380V() {
System.out.println("输出电压:" + output);
return output;
}
}
}
运行结果 :
变压器交流380v转220v三相电变两项电。。。
变压器转换完成:电压输出为:224
缺省适配器
示例代码
public class Adapter3 {
public static void main(String[] args) {
Power power = new Power();
PowerAdapter powerAdapter = new Power220VAdapter(power);
Integer integer = powerAdapter.output220V();
}
// 电压输出
interface PowerTarget {
/**
* 输出电压24V
*
* @return 输出电压
*/
Integer output24V();
/**
* 输出电压110V
*
* @return 输出电压
*/
Integer output110V();
/**
* 输出电压220V
*
* @return 输出电压
*/
Integer output220V();
}
@Data
static abstract class PowerAdapter implements PowerTarget {
protected Power power;
public PowerAdapter(Power power) {
this.power = power;
}
/**
* 输出电压24V
*
* @return 输出电压
*/
@Override
public Integer output24V() {
return 0;
}
/**
* 输出电压110V
*
* @return 输出电压
*/
@Override
public Integer output110V() {
return 0;
}
/**
* 输出电压220V
*
* @return 输出电压
*/
@Override
public Integer output220V() {
return 0;
}
}
// 缺省适配器转换器
static class Power220VAdapter extends PowerAdapter {
public Power220VAdapter(Power power) {
super(power);
}
/**
* 输出电压220V
*
* @return 输出电压
*/
@Override
public Integer output220V() {
Integer output = power.getOutput();
System.out.println("变压器开始转换:" + output + "v转220v三相电变两项电。。。");
double adapter = new Random().nextDouble(1.64, 1.72);
Integer newOutput = (int) (output / adapter);
System.out.println("变压器转换完成:电压输出为:" + newOutput);
return newOutput;
}
}
@Data
static class Power {
private Integer output = 380;
public Integer output380V() {
System.out.println("输出电压:" + output);
return output;
}
}
}
运行结果:
变压器开始转换:380v转220v三相电变两项电。。。
变压器转换完成:电压输出为:224
组合模式---结构型
享元模式---结构型
代理模式---结构型
桥接模式---结构型
策略模式---行为型
常见应用场景
策略模式广泛应用于支付、计算、文件压缩、登录等场景,尤其是在游戏中,如王者荣耀和PUBG的角色处理。值得注意的是,在实际开发中,一种业务场景可能会同时使用多种设计模式,因此,下面的介绍仅为简化并专注于策略模式的核心概念。
策略模式基础介绍
策略模式涉及三个主要角色:
- 抽象策略(Strategy)
- 具体策略(Concrete Strategy)
- 上下文(Context)
其中,Context
的概念较为抽象,通常用来持有策略并在运行时动态地切换策略。
代码实现
策略模式的实现并不复杂,主要是定义三个角色:抽象策略、具体策略和上下文。为了更清晰地展示,我定义了两个具体策略,每个策略执行不同的操作。然后将策略放入上下文中,最终通过上下文来执行具体策略的方法。
public class BaseStrategy {
public static void main(String[] args) {
// 创建具体策略
ConcreteStrategy1 concreteStrategy1 = new ConcreteStrategy1();
ConcreteStrategy2 concreteStrategy2 = new ConcreteStrategy2();
// 通过上下文执行策略
new Context(concreteStrategy1).doIt();
new Context(concreteStrategy2).doIt();
}
// 抽象策略接口
public interface Strategy {
/**
* 执行策略方法
*/
void method();
}
// 具体策略实现1
public static class ConcreteStrategy1 implements Strategy {
@Override
public void method() {
System.out.println("执行具体策略1...");
}
}
// 具体策略实现2
public static class ConcreteStrategy2 implements Strategy {
@Override
public void method() {
System.out.println("执行具体策略2...");
}
}
// 上下文类,持有策略并执行
public static class Context {
private final Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
/**
* 执行策略的方法
*/
public void doIt() {
strategy.method();
}
}
}
执行结果:
执行具体策略1...
执行具体策略2...
示例-游戏角色
需要制作的游戏角色业务需求,基础角色是其他角色的抽象,包括国王、王后、骑士、士兵等,武器是一个接口所有武器都实现这个接口,切换武器(武器有主武器和副武器)可以调用setPrimaryWeapon
和setSubWeapon
。
代码实现
public class GameCharacter {
public static void main(String[] args) {
Character soldier = new Soldier();
soldier.fight();
Character king = new King();
king.setPrimaryWeapon(new AxeWeapon());
king.fight();
}
// 武器接口
interface Weapon {
String function();
}
// 各种武器实现
public static class SwordWeapon implements Weapon {
@Override
public String function() {
return "⚔️ ⚔️ ⚔️";
}
}
public static class AxeWeapon implements Weapon {
@Override
public String function() {
return "🪓 🪓 🪓";
}
}
public static class KnifeWeapon implements Weapon {
@Override
public String function() {
return "🔪 🔪 🔪";
}
}
// 抽象角色类
public abstract static class Character {
String name;
@Setter
private Weapon primaryWeapon;
@Setter
private Weapon subWeapon;
public Character(String name) {
this.name = name;
// 默认武器配置
this.primaryWeapon = new SwordWeapon();
this.subWeapon = new KnifeWeapon();
}
void fight() {
if (primaryWeapon != null && subWeapon != null) {
String primary = primaryWeapon.function();
String sub = subWeapon.function();
System.out.println(name + ":" + primary + "和" + sub);
} else {
System.out.println(name + "没有武器!");
}
}
}
// 国王角色
public static class King extends Character {
public King() {
super("King");
setPrimaryWeapon(new SwordWeapon());
setSubWeapon(new KnifeWeapon());
}
}
// 士兵角色
public static class Soldier extends Character {
public Soldier() {
super("Soldier");
setPrimaryWeapon(new AxeWeapon());
setSubWeapon(new SwordWeapon());
}
}
}
运行结果:
Soldier:🪓 🪓 🪓和⚔️ ⚔️ ⚔️
King:🪓 🪓 🪓和🔪 🔪 🔪
观察者模式---行为型
观察者有四个角色,观察者(Observe)和具体观察者(Concrete Observe)、主题(Subject)和具体主题(Concrete Subject),具体观察者和具体主题可以多个。
简单示例
其中主题中有3个方法,添加(或者理解成注册都可以)、移出、通知,差不多都是这三个方法,其中添加可以理解成注册加入总之是往数组中添加观察者。
代码实现
public class ObserverDemo {
public static void main(String[] args) {
// 定义的主题
News news = new News();
// 观察者
SisterObserver sisterObserver = new SisterObserver();
GirlfriendObserver girlfriendObserver = new GirlfriendObserver();
// 添加观察者
news.addObserver(sisterObserver);
news.notifyObservers("添加了妹妹");
System.out.println("\n-----------------分割线-----------------\n");
// 添加女朋友
news.addObserver(girlfriendObserver);
news.notifyObservers("添加了女朋友");
System.out.println("\n-----------------分割线-----------------\n");
news.removeObserver(girlfriendObserver);
news.notifyObservers("需要和妹妹说点悄悄话,将女朋友移除了,这时女朋友听不见我们说话。。。");
}
// 观察者接口
@FunctionalInterface
interface Observer {
void update(String message);
}
// 主题接口
interface Subject {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers(String message);
}
// 妹妹观察者
static class SisterObserver implements Observer {
@Override
public void update(String message) {
System.out.println("SisterObserver 接受到消息:" + message);
}
}
// 女朋友观察者
static class GirlfriendObserver implements Observer {
@Override
public void update(String message) {
System.out.println("GirlfriendObserver 接受到消息:" + message);
}
}
// 主题类
static class News implements Subject {
private final List<Observer> observerList = new ArrayList<>();
@Override
public void addObserver(Observer observer) {
observerList.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observerList.remove(observer);
}
@Override
public void notifyObservers(String message) {
for (Observer observer : observerList) {
observer.update(message);
}
}
}
}
运行结果:
SisterObserver 接受到消息:添加了妹妹
-----------------分割线-----------------
SisterObserver 接受到消息:添加了女朋友
GirlfriendObserver 接受到消息:添加了女朋友
-----------------分割线-----------------
SisterObserver 接受到消息:需要和妹妹说点悄悄话,将女朋友移除了,这时女朋友听不见我们说话。。。
命令模式---行为型
Command:定义执行请求的接口(或抽象类)。
ConcreteCommand:实现命令接口并具体化执行请求的过程,通常还会持有接收者对象。
Receiver:具体的对象,完成实际的操作任务。
Invoker:调用命令的对象,触发命令的执行。
Client:客户端,负责创建并配置命令对象,将命令与接收者绑定,并传递给调用者执行。
简单示例
示例代码
public class CommandDemo {
public static void main(String[] args) {
Receiver receiver = new Receiver();
ConcreteCommand concreteCommand = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(concreteCommand);
invoker.invoke();
}
// 命令接口
interface Command {
/**
* 执行方法
*/
void execute();
}
// 接受者
static class Receiver {
public void action() {
System.out.println("接受者 执行。。。");
}
}
// 具体的执行命令
static class ConcreteCommand implements Command {
private final Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
/**
* 执行方法
*/
@Override
public void execute() {
receiver.action();
}
}
@Setter
static class Invoker {
private Command command;
public void invoke() {
command.execute();
}
}
}
执行结果:
接受者 执行。。。
示例-烧烤店
示例代码
public class BakeDemo {
// 充当客户端
public static void main(String[] args) {
Waiter waiter = new Waiter();
Barbecue barbecue = new Barbecue();
waiter.addCommand(new BakeChickenWing(barbecue));
waiter.addCommand(new BakeMutton(barbecue));
waiter.notifyCommand();
}
// 接受者-厨师
static class Barbecue {
/**
* 烤串
*/
public void bakeMutton() {
System.out.println("开始烤串。。。");
}
/**
* 烤鸡翅
*/
public void bakeChickenWing() {
System.out.println("开始烤鸡翅。。。");
}
}
// 请求者-invoker-服务员
public static class Waiter {
private final List<Command> commandList = new ArrayList<>();
public void addCommand(Command command) {
commandList.add(command);
}
/**
* 通知厨师开始制作
*/
public void notifyCommand() {
for (Command command : commandList) {
command.execute();
}
}
}
public static abstract class Command {
protected Barbecue barbecue;
public Command(Barbecue barbecue) {
this.barbecue = barbecue;
}
/**
* 执行方法
*/
public abstract void execute();
}
// 命令-烤鸡翅
public static class BakeChickenWing extends Command {
public BakeChickenWing(Barbecue barbecue) {
super(barbecue);
}
/**
* 执行方法
*/
@Override
public void execute() {
barbecue.bakeChickenWing();
}
}
// 命令-烤串
public static class BakeMutton extends Command {
public BakeMutton(Barbecue barbecue) {
super(barbecue);
}
/**
* 执行方法
*/
@Override
public void execute() {
barbecue.bakeMutton();
}
}
}
执行结果:
开始烤鸡翅。。。
开始烤串。。。
状态模式---行为型
模板方法模式---行为型
将定义好的按步骤执行的内容进行封装,模板方法是比较单间的设计模式,是代码复用的基本技术,在类库中尤其重要,遵循:“抽象类应当拥有尽可能多的可能性,应当拥有尽可能少的数据”。
需要的角色:抽象类(Abstract Class)、具体类(Concrete Class)。
比如做一些比较固定的事情(支付流程处理),但是其中几项内容可能会发生改变。
简单示例
示例代码
public class PaymentProcess {
public static void main(String[] args) {
ConcretePaymentProcess concretePaymentProcess = new ConcretePaymentProcess();
concretePaymentProcess.startProcess();
}
// 抽象模板方法
static abstract class AbstractPaymentProcess {
/**
* 开始流程
*/
public void startProcess() {
authenticationUser();
checkBalance();
executePayment();
returnPayment();
}
/**
* 验证用户身份
*/
private void authenticationUser() {
System.out.println("验证用户身份。。。");
}
/**
* 检查余额
*/
public abstract void checkBalance();
/**
* 执行支付
*/
private void executePayment() {
System.out.println("执行支付。。。");
}
/**
* 返回支付结果
*/
public abstract void returnPayment();
}
static class ConcretePaymentProcess extends AbstractPaymentProcess {
/**
* 检查余额
*/
@Override
public void checkBalance() {
System.out.println("检查完成,我的余额还有:1999亿元");
}
/**
* 返回支付结果
*/
@Override
public void returnPayment() {
System.out.println("支付成功,我的余额还有:1994亿元");
}
}
}
运行结果:
验证用户身份。。。
检查完成,我的余额还有:1999亿元
执行支付。。。
支付成功,我的余额还有:1994亿元
备忘录模式---行为型
定义:在不破坏封闭的前提下,捕获一个对象内部状态,并在该对象之外保存这个状态,这样以后就将该对象恢复到原先保存的状态。
需要角色:Originator(发起人)、Memento(备忘录)、Caretaker(管理者)
备忘录可以实现功能:撤销、重做、历史记录、快照。
简单示例
示例代码
public class Memo {
public static void main(String[] args) {
// 定义记事本
NoteEditText noteEditText = new NoteEditText();
// 负责管理记事本
NoteCaretaker noteCaretaker = new NoteCaretaker();
// 写入记录
noteEditText.content = "创建第一条记录。。。";
noteCaretaker.saveMemo(noteEditText.createMemo());
// 再次写入
noteEditText.content = "第三条记录。。。";
noteCaretaker.saveMemo(noteEditText.createMemo());
// 写错撤销下
noteEditText.restoreMemo(noteCaretaker.getPrevMemo());
}
// 备忘录角色-备忘录
@Getter
static class Memento {
private final String content;
public Memento(String content) {
this.content = content;
}
}
// 存储备忘录--管理者
static class NoteCaretaker {
private final List<Memento> mementoList = new ArrayList<>();
// 存档位置
private int index = 0;
/**
* 添加内容到备忘录中
*
* @param memento 备忘录
*/
public void saveMemo(Memento memento) {
mementoList.add(memento);
index = mementoList.size() - 1;
for (Memento memento1 : mementoList) {
System.out.print(memento1.content + " ");
}
System.out.println();
}
/**
* 获取下一个
*
* @return 备忘录
*/
public Memento getNextMemo() {
index = index > (mementoList.size() - 1) ? index : mementoList.size() - 1;
return mementoList.get(index);
}
/**
* 获取上一个
*
* @return 备忘录
*/
public Memento getPrevMemo() {
index = index > 0 ? (index - 1) : 0;
return mementoList.get(index);
}
}
// 负责创建备忘录-发起人
@Data
static class NoteEditText {
private String content;
public Memento createMemo() {
return new Memento(content);
}
public void restoreMemo(Memento memento) {
this.content = memento.content;
System.out.println("撤销记录:" + content);
}
}
}
运行结果:
创建第一条记录。。。
创建第一条记录。。。 第三条记录。。。
撤销记录:创建第一条记录。。。
中介者模式---行为型
迭代器模式---行为型
访问者模式---行为型
解释器模式---行为型
责任链模式---行为型-未完成。。。
主要有两个角色:抽象处理者(Handler)、具体处理者(Concrete Handler)
简单示例
代码示例
public class Chain {
// 过滤垃圾请求,为了演示需要清除【垃圾,辣鸡,腊鸡】这些词
public static void main(String[] args) {
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
Handler handlerC = new ConcreteHandlerC();
// 设置责任链
handlerA.setNextHandler(handlerB);
handlerB.setNextHandler(handlerC);
// 发起请求
handlerA.handleRequest("过滤垃圾请求,为了演示需要清除【垃圾,辣鸡,腊鸡】这些词");
}
// ConcreteHandler类
static class ConcreteHandlerA extends Handler {
@Override
public void handleRequest(String request) {
// 处理"垃圾"
String updatedRequest = request.replaceAll("垃圾", "");
System.out.println("Handler A处理后: " + updatedRequest);
if (nextHandler != null) {
nextHandler.handleRequest(updatedRequest); // 传递修改后的请求
}
}
}
static class ConcreteHandlerB extends Handler {
@Override
public void handleRequest(String request) {
// 处理"辣鸡"
String updatedRequest = request.replaceAll("辣鸡", "");
System.out.println("Handler B处理后: " + updatedRequest);
if (nextHandler != null) {
nextHandler.handleRequest(updatedRequest); // 传递修改后的请求
}
}
}
static class ConcreteHandlerC extends Handler {
@Override
public void handleRequest(String request) {
// 处理"腊鸡"
String updatedRequest = request.replaceAll("腊鸡", "");
System.out.println("Handler C处理后: " + updatedRequest);
if (nextHandler != null) {
nextHandler.handleRequest(updatedRequest); // 传递修改后的请求
}
}
}
// Handler类
@Setter
abstract static class Handler {
protected Handler nextHandler;
public abstract void handleRequest(String request);
}
}
运行结果:
Handler A处理后: 过滤请求,为了演示需要清除【,辣鸡,腊鸡】这些词
Handler B处理后: 过滤请求,为了演示需要清除【,,腊鸡】这些词
Handler C处理后: 过滤请求,为了演示需要清除【,,】这些词