常见的十二种设计模式
1.单例模式(Singleton Pattern)
保证一个类只有一个实例,并提供全局访问点
代码实现
package com.cw.daydayup.design;
/**
* @author thisdcw-com
* @date 2023/12/9 14:48
*/
public class SingletonPattern {
/**
* 单例模式:
* <p>
* Singleton类有一个私有的静态变量instance,构造方法私有化,以防外部直接实例化
* 提供一个公共的静态getInstance方法, 全局使用这个唯一实例
* 如果实例存在就返回实例,不存在就创建实例
*/
private static SingletonPattern instance;
private SingletonPattern() {
}
public static SingletonPattern getInstance() {
if (instance == null) {
instance = new SingletonPattern();
}
return instance;
}
}
2.工厂模式(Factory Pattern)
定义一个接口用于创建对象,但让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类
代码实现
package com.cw.daydayup.design;
/**
* @author thisdcw-com
* @date 2023/12/9 14:51
*/
public class FactoryPattern {
/**
* 工厂模式:
* <p>
* 使用工厂模式可以通过工厂接口创建产品,不需要知道具体的产品实现类,是一种松耦合的设计
* 允许系统更容易扩展,添加新的产品或工厂时无需修改客户端代码
*/
//产品接口
interface Product {
void create();
}
//产品A
class ProductA implements Product {
@Override
public void create() {
System.out.println("生产产品A");
}
}
//产品B
class ProductB implements Product {
@Override
public void create() {
System.out.println("生产产品B");
}
}
//工厂接口
interface Factory {
Product createProduct();
}
//A工厂
class FactoryA implements Factory {
@Override
public Product createProduct() {
return new ProductA();
}
}
//B工厂
class FactoryB implements Factory {
@Override
public Product createProduct() {
return new ProductB();
}
}
}
3.抽象工厂模式(Abstract Factory Pattern)
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类
代码实现
package com.cw.daydayup.design;
/**
* @author thisdcw-com
* @date 2023/12/9 14:58
*/
public class AbstractFactoryPattern {
/**
* 抽象工厂模式
* <p>
* 客户端通过抽象工厂接口创建产品,无需关心具体的产品实现类
* 有助于保持产品家族的一致性,确保创建的产品是互相关联的
* <p>
* 和普通工厂模式的区别:
* 1.目标不同:
* - 工厂模式: 主要关注单一类型的对象,一个工厂类只负责创建一种产品
* - 抽象工厂模式: 关注创建一系列相关或互相依赖的对象家族,而不关心具体的产品类
* 2.产品等级结构不同:
* - 工厂模式: 创建单一系列的产品
* - 抽象工厂模式: 创建一系列相关的产品,形成产品家族
* 3.接口数量不同:
* - 工厂模式: 只有一个工厂接口
* - 抽象工厂模式: 有多个相关的工厂接口,每个接口负责一个产品家族
* 4.使用场景不同:
* - 工厂模式: 适用于需要创建单一类型对象,但客户端不关心具体实例的创建过程
* - 抽象工厂模式: 适用于需要创建一系列相关对象,且客户端希望这些对象能够协同工作
* <p>
* 示例:
* - 工厂模式:一个披萨店只能生产披萨
* - 抽象工厂模式:一个餐厅可能生产多种不同种类的彩品(产品家族)
*/
//抽象产品A接口
interface ProductA {
void create();
}
//生产产品A1
class CreateProductA1 implements ProductA {
@Override
public void create() {
System.out.println("生产产品A1");
}
}
//生产产品A2
class CreateProductA2 implements ProductA {
@Override
public void create() {
System.out.println("生产产品A2");
}
}
//抽象产品B接口
interface ProductB {
void create();
}
//生产产品B1
class CreateProductB1 implements ProductB {
@Override
public void create() {
System.out.println("生产产品B1");
}
}
//生产产品B2
class CreateProductB2 implements ProductB {
@Override
public void create() {
System.out.println("生产产品B2");
}
}
//抽象工厂接口
interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
//工厂1
class Factory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new CreateProductA1();
}
@Override
public ProductB createProductB() {
return new CreateProductB1();
}
}
//工厂2
class Factory2 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new CreateProductA2();
}
@Override
public ProductB createProductB() {
return new CreateProductB2();
}
}
}
4.建造者模式(Builder Pattern)
将一个复杂对象的构建与它的表示分离,使同样的构建过程可以创建不同的表示
代码实现
package com.cw.daydayup.design;
/**
* @author thisdcw-com
* @date 2023/12/9 15:36
*/
public class BuilderPattern {
/**
* 建造者模式
* <p>
* 客户端使用指导者来构建不同配置的计算机,不需要知道具体的构建过程,有助于创建不同配置的对象,同时保证构建过程的独立性
*/
//计算机类
class Computer {
private String cpu;
private String memory;
private String storage;
public void setCpu(String cpu) {
this.cpu = cpu;
}
public void setMemory(String memory) {
this.memory = memory;
}
public void setStorage(String storage) {
this.storage = storage;
}
//其他方法...
}
//抽象计算机建造者工厂
interface ComputerBuilder {
void buildCpu();
void buildMemory();
void buildStorage();
Computer getResult();
}
//具体创建者1
class Builder1 implements ComputerBuilder {
private Computer computer = new Computer();
@Override
public void buildCpu() {
computer.setCpu("i9-14900KF");
}
@Override
public void buildMemory() {
computer.setMemory("128GB");
}
@Override
public void buildStorage() {
computer.setStorage("4TB");
}
@Override
public Computer getResult() {
return computer;
}
}
//具体创建者2
class Builder2 implements ComputerBuilder {
private Computer computer = new Computer();
@Override
public void buildCpu() {
computer.setCpu("i5-12490F");
}
@Override
public void buildMemory() {
computer.setMemory("16GB");
}
@Override
public void buildStorage() {
computer.setStorage("2TB");
}
@Override
public Computer getResult() {
return computer;
}
}
//指导者
class Director {
public Computer construct(ComputerBuilder builder) {
builder.buildCpu();
builder.buildMemory();
builder.buildStorage();
return builder.getResult();
}
}
}
5.原型模式(Prototype Pattern)
用原型实例指定创建对象的种类,并通过复制这些原型创建新的对象
代码实现
package com.cw.daydayup.design;
/**
* @author thisdcw@gmail.com
* @date 2023/12/9 19:47
*/
public class PrototypePattern {
/**
* 原型模式
* <p>
* 好处:
* 1.对象复制: 允许在运行时动态复制对象,无需依赖具体类,可根据需要创建和配置新对象,无需从头开始
* 2.性能优化: 避免重复的初始化工作
* 3.简化对象创建: 简化对象的创建过程
* 4.动态配置对象: 克隆操作还可以根据需要轻松创建不同配置的对象
* 5.隐藏细节: 客户端代码专注于与抽象接口交互,无需了解对象的内部构造
*/
//原型接口
interface Prototype {
Prototype clone();
void displayInfo();
}
//具体原型
class CreatPrototype implements Prototype {
private String data;
public CreatPrototype(String data) {
this.data = data;
}
//创建一个相同数据的对象
@Override
public Prototype clone() {
return new CreatPrototype(this.data);
}
@Override
public void displayInfo() {
System.out.println("数据: " + data);
}
}
//客户端代码
public void example() {
//创建原始对象
CreatPrototype original = new CreatPrototype("原始数据");
//克隆原始对象
CreatPrototype clone = (CreatPrototype) original.clone();
//显示原始和克隆对象的信息
original.displayInfo();
clone.displayInfo();
}
}
6.适配器模式(Adapter Pattern)
将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
代码实现
package com.cw.daydayup.design;
/**
* @author thisdcw-com
* @date 2023/12/9 15:50
*/
public class AdapterPattern {
/**
* 适配器模式
* <p>
* 实例中:
* 可以让原有的Mp3Player能够播放其他格式的音频文件
*/
//目标接口
interface MediaPlayer {
void play(String audioType, String filename);
}
//具体类,只适用于MP3
class Mp3Player implements MediaPlayer {
@Override
public void play(String audioType, String filename) {
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("playing mp3 file: " + filename);
} else {
System.out.println("UnSupport mediaType: " + audioType);
}
}
}
//适配器接口,用于支持其他音频格式
interface AdvancedMediaPlayer {
void playVlc(String filename);
void playMp4(String filename);
}
//具体类实现vlc
class VlcPlayer implements AdvancedMediaPlayer {
@Override
public void playVlc(String filename) {
System.out.println("Playing VLC file: " + filename);
}
@Override
public void playMp4(String filename) {
}
}
//具体类实现Mp4
class Mp4Player implements AdvancedMediaPlayer {
@Override
public void playVlc(String filename) {
}
@Override
public void playMp4(String filename) {
System.out.println("Playing mp4 file: " + filename);
}
}
//适配器类,将AdvancedMediaPlayer适配到MediaPlayer接口
class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMediaPlayer;
public MediaAdapter(String audioType) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMediaPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMediaPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String filename) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMediaPlayer.playVlc(filename);
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMediaPlayer.playMp4(filename);
} else {
System.out.println("UnSupport audio type: " + audioType);
}
}
}
}
7.装饰者模式(Decorator Pattern)
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活
代码实现
package com.cw.daydayup.design;
/**
* @author thisdcw-com
* @date 2023/12/9 16:35
*/
public class DecoratorPattern {
/**
* 装饰者模式
* 示例:
* 假设有一个咖啡店,你可以点一杯咖啡并添加不同的调料
* <p>
* 在example方法中,你可以动态地,灵活地为咖啡对象添加不同的调料,不需要修改原来的类
*/
//咖啡接口
interface Coffee {
String getDescription();
double cost();
}
//具体的咖啡类
class SimpleCoffee implements Coffee {
@Override
public String getDescription() {
return "Simple Coffee";
}
@Override
public double cost() {
return 2.0;
}
}
//装饰者抽象类
abstract class CoffeeDecorator implements Coffee {
protected Coffee decorateCoffee;
public CoffeeDecorator(Coffee decorateCoffee) {
this.decorateCoffee = decorateCoffee;
}
@Override
public String getDescription() {
return decorateCoffee.getDescription();
}
@Override
public double cost() {
return decorateCoffee.cost();
}
}
//具体的装饰者,加奶
class MilkDecorate extends CoffeeDecorator {
public MilkDecorate(Coffee decorateCoffee) {
super(decorateCoffee);
}
@Override
public String getDescription() {
return super.getDescription() + ", with milk";
}
@Override
public double cost() {
return super.cost() + 0.5;
}
}
class SugarDecorate extends CoffeeDecorator {
public SugarDecorate(Coffee decorateCoffee) {
super(decorateCoffee);
}
@Override
public String getDescription() {
return super.getDescription() + ", with sugar";
}
@Override
public double cost() {
return super.cost() + 0.2;
}
}
public void example() {
//创建一杯简单的咖啡
Coffee coffee = new SimpleCoffee();
System.out.println("Description: " + coffee.getDescription() + ", cost: $" + coffee.cost());
//加奶
Coffee milkCoffee = new MilkDecorate(coffee);
System.out.println("Description: " + milkCoffee.getDescription() + ", cost: $" + milkCoffee.cost());
//加糖
Coffee sugarCoffee = new SugarDecorate(milkCoffee);
System.out.println("Description: " + sugarCoffee.getDescription() + ", cost: $" + sugarCoffee.cost());
}
}
8.观察者模式(Observer Pattern)
定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新
代码实现
package com.cw.daydayup.design;
import java.util.ArrayList;
import java.util.List;
/**
* @author thisdcw-com
* @date 2023/12/9 16:52
*/
public class ObserverPattern {
/**
* 观察者模式
* <p>
* 在示例中:
* Subject是主题接口,定义了添加,删除和通知观察者的方法
* CreateSubject是具体的主题类,包含一个状态和一个观察者列表,状态变化时通知观察者
* Observer是观察者接口定义了更新方法
* CreateObserver是具体的观察类,被创建时会注册到主题,主题状态变化时,观察者会得到通知并执行相应的更新操作
* <p>
* 使用观察者模式,可以实现对象之间的松耦合,当一个对象状态发生变化时,其他依赖它的对象可以及时获得通知并做出相应的反应
* <p>
* 在example方法中当CreateSubject的状态变化时,两个观察者CreateObserver会收到更新通知
*/
//主体接口
interface Subject {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObserver();
}
//具体主题类
class CreateSubject implements Subject {
private int state;
private List<Observer> observers = new ArrayList<>();
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyObserver();
}
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObserver() {
for (Observer observer : observers) {
observer.update();
}
}
}
//观察者接口
interface Observer {
void update();
}
//具体观察类
class CreateObserver implements Observer {
private CreateSubject subject;
public CreateObserver(CreateSubject subject) {
this.subject = subject;
subject.addObserver(this);
}
@Override
public void update() {
System.out.println("Observer updated with state: " + subject.getState());
}
}
public void example() {
CreateSubject subject = new CreateSubject();
CreateObserver observer1 = new CreateObserver(subject);
CreateObserver observer2 = new CreateObserver(subject);
subject.setState(1);
subject.setState(2);
}
}
9.策略模式(Strategy Pattern)
定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换
代码实现
package com.cw.daydayup.design;
/**
* @author thisdcw-com
* @date 2023/12/9 17:13
*/
public class StrategyPattern {
/**
* 策略模式
* <p>
* 示例中:
* DiscountStrategy是策略接口
* DiscountStrategy1 和 DiscountStrategy2 是具体的策略类
* ShoppingCart是一个上下文类,维护一个策略引用
* <p>
* 使用策略模式可以动态的在运行时选择不同的折扣策略而不需要修改客户端代码,
* 可以灵活的切换不同的折扣策略,不影响购物车的其他部分
*/
//策略接口
interface DiscountStrategy {
double applyDiscount(double originalPrice);
}
//具体策略1:打折策略
class DiscountStrategy1 implements DiscountStrategy {
private double discountRate;
public DiscountStrategy1(double discountRate) {
this.discountRate = discountRate;
}
@Override
public double applyDiscount(double originalPrice) {
return originalPrice * (1 - discountRate);
}
}
//具体策略2:满减策略
class DiscountStrategy2 implements DiscountStrategy {
private double threshold;//满多少
private double discountAmount;//减多少
public DiscountStrategy2(double threshold, double discountAmount) {
this.threshold = threshold;
this.discountAmount = discountAmount;
}
@Override
public double applyDiscount(double originalPrice) {
if (originalPrice > threshold) {
return originalPrice - discountAmount;
}
return originalPrice;
}
}
//上下文类,维护策略引用
class ShoppingCart {
private DiscountStrategy discountStrategy;
public void setDiscountStrategy(DiscountStrategy discountStrategy) {
this.discountStrategy = discountStrategy;
}
public double checkout(double totalPrice) {
return discountStrategy.applyDiscount(totalPrice);
}
}
public void example() {
ShoppingCart cart = new ShoppingCart();
//选择打折策略
cart.setDiscountStrategy(new DiscountStrategy1(0.1));
double discountPrice1 = cart.checkout(100.0);
System.out.println("Discount price 1: $ " + discountPrice1);
//选择满减策略
cart.setDiscountStrategy(new DiscountStrategy2(50.0, 10.0));
double discountPrice2 = cart.checkout(60.0);
System.out.println("Discount price 2: $ " + discountPrice2);
}
}
10.状态模式(State Pattern)
允许一个对象在其内部状态改变时改变它的行为
代码实现
package com.cw.daydayup.design;
/**
* @author thisdcw-com
* @date 2023/12/9 17:31
*/
public class StatePattern {
/**
* 状态模式
* <p>
* 示例中:
* State是状态接口
* NormalState和BoldState是具体的状态类
* Editor是上下文类,维护当前状态
* <p>
* 可以动态地改变文档编辑器的编辑状态,而不需要在客户端代码中使用条件语句
*/
//状态接口
interface State {
void handleRequest();
}
//具体状态: 正常编辑状态
class NormalState implements State {
@Override
public void handleRequest() {
System.out.println("normal editing state");
}
}
//具体状态: 粗体编辑状态
class BoldState implements State {
@Override
public void handleRequest() {
System.out.println("bold editing state");
}
}
//上下文类,维护当前状态
class Editor {
private State currentState;
public Editor() {
currentState = new NormalState();
}
public void setState(State state) {
this.currentState = state;
}
public void request() {
currentState.handleRequest();
}
}
public void example() {
Editor editor = new Editor();
//正常编辑状态
editor.request();
//切换到粗体编辑状态
editor.setState(new BoldState());
editor.request();
}
}
11.代理模式(Proxy Pattern)
控制对其他对象的访问,允许在访问对象时添加额外的操作
代码实现
package com.cw.daydayup.design;
/**
* @author thisdcw@gmail.com
* @date 2023/12/9 19:58
*/
public class ProxyPattern {
/**
* 代理模式
* <p>
* 在实例中:
* 客户端代码可以直接访问真实主题或者通过代理访问
* <p>
* 潜在的好处:
* <p>
* 1.控制访问: 控制对实际对象的访问,充当一个中介,可以在调用实际对象之前或者之后执行额外的操作
* 2.延迟加载: 延迟加载实际对象,即在需要的时候才创建,提高程序的性能
* 3.简化接口: 提供一个简化版的接口,隐藏实际对象的复杂性.客户端无需了解或者处理与实际对象相关的复杂逻辑
* 4.实现懒加载: 减少启动时间,避免不必要的资源消耗
* 5.实现缓存: 代理可以维护一个缓存,储存先前对实际对象调用结果,提高相同请求的响应速度
*/
//主题接口
interface Subject {
void request();
}
//具体主题
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("处理真实请求");
}
}
//代理
class Proxy implements Subject {
private RealSubject realSubject;
@Override
public void request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
System.out.println("通过代理访问真实主题");
realSubject.request();
}
}
public void example() {
//直接访问真实主题
RealSubject realSubject = new RealSubject();
realSubject.request();
System.out.println("======================================");
//通过代理访问真实主题
Proxy proxy = new Proxy();
proxy.request();
}
}
12.命令模式(Command Pattern)
将请求封装成对象,以便参数化客户,并支持对请求排队、请求日志和可撤销的操作
代码实现
package com.cw.daydayup.design;
/**
* @author thisdcw@gmail.com
* @date 2023/12/9 20:14
*/
public class CommandPattern {
/**
* 命令模式
* <p>
* 好处:
* 1.解耦发送者和接受者: 发送者不需要知道命令如何执行的,只需知道如何发送
* 2.支持撤销和恢复操作: 命令对象可以存储先前的状态和操作
* 3.灵活性和扩展性: 轻松添加新的命令类,无需修改现有的发送者和接受者
* 4.日志和事务: 可以记录命令的执行历史,有助于系统监控和维护
* 5.队列请求: 可用于构建队列,支持批处理和延迟执行
*/
//命令接口
interface Command {
void execute();
}
//具体命令
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
}
//接受者
class Light {
public void turnOn() {
System.out.println("灯开了");
}
public void turnOff() {
System.out.println("灯关了");
}
}
//调用者
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
public void example() {
Light light = new Light();
Command lightOnCommand = new LightOnCommand(light);
//设置命令
RemoteControl remoteControl = new RemoteControl();
remoteControl.setCommand(lightOnCommand);
//调用者通过命令执行
remoteControl.pressButton();
}
}
原文链接
https://thisdcw.asia/archives/1702124846121