前言
设计模式是软件开发中常见问题的解决方案,它们是经过验证的并且经常被重复使用的设计模板
。设计模式提供了一套通用的解决方案,帮助开发人员构建高质量、可维护和可扩展
的代码。设计模式并不是特定于某种编程语言,而是面向对象编程范式的通用原则
一. 设计模式的类型
创建型模式(Creational Patterns)
这类设计模式关注如何创建对象
,旨在解决对象创建的灵活性和复杂性
。包括了单例模式、工厂模式、抽象工厂模式
、建造者模式和原型模式
- 单例模式(Singleton Pattern):确保一个类
只有一个实例
,并提供全局访问点 - 工厂模式(Factory Pattern):定义一个用于创建对象的接口,由
子类决定要实例化的类
- 抽象工厂模式(Abstract Factory Pattern):提供一个接口,用于创建相关或依赖对象的家族,而无需明确指定具体类
- 建造者模式(Builder Pattern):将一个
复杂对象的构建与其表示分离
,使同样的构建过程可以创建不同的表示 - 原型模式(Prototype Pattern):通过复制现有对象来创建新对象,而无需知道其具体类
结构型模式(Structural Patterns)
这类设计模式关注如何将类和对象组合成更大的结构,以解决系统中不同类和对象之间的灵活性和复杂性问题
。包括了适配器模式、装饰器模式、代理模式、组合模式、外观模式、桥接模式和享元模式
- 适配器模式(Adapter Pattern):将一个类的接口转换成客户端所期望的另一个接口
- 装饰器模式(Decorator Pattern):动态地将责任添加到对象上,以扩展功能
- 代理模式(Proxy Pattern):为其他对象提供一个代理,以控制对这个对象的访问
- 组合模式(Composite Pattern):将对象组合成树形结构以表示"部分-整体"的层次结构
- 外观模式(Facade Pattern):提供一个统一的接口,用于访问子系统中的一群接口
- 桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们可以独立地变化
- 享元模式(Flyweight Pattern):通过共享对象来减少内存的使用
行为型模式(Behavioral Patterns)
这类设计模式关注对象之间的通信和职责分配,以解决类和对象之间的高效沟通和合作问题
它包括了观察者模式、策略模式、命令模式、模板方法模式、迭代器模式、责任链模式、状态模式和访问者模式
- 观察者模式(Observer Pattern):定义了一对多的依赖关系,当一个对象的状态改变时,其所有依赖对象都会收到通知并自动更新
- 策略模式(Strategy Pattern):定义一系列算法,将每个算法封装起来,并使它们可以相互替换
- 命令模式(Command Pattern):将请求封装成一个对象,从而使不同的请求参数化,并支持请求的排队、记录和撤销
- 模板方法模式(Template Method Pattern):定义一个算法的骨架,将一些步骤延迟到子类中
- 迭代器模式(Iterator Pattern):提供一种方法顺序访问一个聚合对象中的各个元素
- 责任链模式(Chain of Responsibility Pattern):将请求的发送和接收解耦,允许多个对象都有机会处理请求
- 状态模式(State Pattern):允许对象在其内部状态改变时改变其行为
- 访问者模式(Visitor Pattern):在不改变数据结构的前提下,增加新的操作,即将处理从数据结构分离出来
最常用的七种设计模式如下:
- 单例模式(Singleton Pattern)
- 工厂模式(Factory Pattern)
- 观察者模式(Observer Pattern)
- 策略模式(Strategy Pattern)
- 适配器模式(Adapter Pattern)
- 装饰器模式(Decorator Pattern)
- 命令模式(Command Pattern)
二. 软件设计七大原则
软件设计七大原则,也称为SOLID原则
,是一组面向对象设计的指导原则,旨在帮助开发人员编写可维护、可扩展和易于理解的代码。这些原则和设计模式
密切相关,它们共同为面向对象编程提供了一套综合的指导方针。SOLID 是一组面向对象编程和设计原则的首字母缩略词
,即下列前五种设计原则中的首字母
以下是SOLID原则的简要介绍和与设计模式的关系:
-
单一职责原则(Single Responsibility Principle):
一个类应该只有一个引起变化的原因。这意味着一个类应该只负责一项职责
。遵循单一职责原则可以提高类的内聚性和可维护性
关系设计模式:
单例模式、工厂模式、观察者模式
等,这些设计模式都帮助实现单一职责原则,将不同的功能拆分到不同的类中。 -
开放封闭原则(Open/Closed Principle):
软件实体(类、模块、函数等)应该对扩展开放,对修改封闭
。这意味着应该通过扩展现有的代码来引入新功能,而不是直接修改现有的代码关系设计模式:
策略模式、装饰器模式、观察者模式
等,这些设计模式支持开放封闭原则,通过定义接口、抽象类和组合来实现可扩展性 -
里氏替换原则(Liskov Substitution Principle):
子类对象应该能够替换其基类对象,而不影响程序的正确性
。即在不改变程序正确性的前提下,派生类可以扩展基类的功能关系设计模式:
工厂模式、模板方法模式
等,这些设计模式利用了子类替换基类的特性,让代码更加灵活和可扩展 -
接口隔离原则(Interface Segregation Principle):
客户端不应该强迫依赖于它们不使用的接口。一个类不应该依赖于它不需要的接口关系设计模式:
适配器模式、策略模式
等,这些设计模式帮助实现接口隔离原则,将大接口拆分成多个小接口,让类只依赖于需要的接口 -
依赖倒置原则(Dependency Inversion Principle):
高层模块不应该依赖于低层模块,而是应该依赖于抽象
。抽象不应该依赖于具体实现细节,而是具体实现应该依赖于抽象关系设计模式:
依赖注入、工厂模式
等,这些设计模式遵循依赖倒置原则,通过依赖抽象而不是具体实现来降低模块之间的耦合 -
合成复用原则(Composition/Aggregation Reuse Principle):
优先使用对象组合或聚合,而不是继承来达到代码复用的目的
。通过组合关系,可以更灵活地增加、删除或替换组件关系设计模式:
装饰器模式、组合模式
等,这些设计模式强调对象组合或聚合,而不是继承来实现代码复用 -
迪米特法则(Law of Demeter,最少知识原则):
一个对象应该对其他对象有尽可能少的了解。即一个类应该尽量减少与其他类之间的交互,尽量降低耦合性
关系设计模式:
外观模式、中介者模式
等,这些设计模式帮助减少对象之间的直接交互,通过引入中间类来降低类之间的耦合度
软件设计原则的目的:
降低对象之间的耦合性和复杂度,提升对象的内聚性,增加程序的可复用性、可扩展性和可维护性
三. 设计模式详解
1. 单例模式(Singleton Pattern)
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例
。这样可以避免多次实例化相同类的对象,节省内存资源,并确保在整个应用程序中只有一个共享的实例被使用
详细介绍
在单例模式中,有几个重要的要点需要考虑:
-
私有的构造函数: 为了防止在外部类中直接实例化对象,单例类的构造函数应该设为私有的,这样其他类就无法通过
new
操作符创建该类的对象 -
静态成员变量: 单例类需要一个静态成员变量来保存唯一实例的引用,确保全局唯一性
-
静态获取方法: 单例类应该提供一个静态的、公共的方法来获取该类的唯一实例。这个方法通常命名为
getInstance()
-
延迟初始化: 在首次调用
getInstance()
方法时才创建实例,而不是在类加载时就创建实例,这样可以实现延迟初始化,提高性能 -
线程安全:
需要考虑多线程环境下的并发访问问题。可以使用同步机制来保证线程安全,但需要注意性能开销
代码示例
package com.zhouquan.entity;/*** @author ZhouQuan* @description 单例模式* @date 2023-07-23 09:57**/
public class Singleton {/*** 私有的静态成员变量,用于保存唯一实例的引用*/private static Singleton instance;/*** 私有的构造函数,防止外部类实例化*/private Singleton() {}/*** 静态的获取实例方法** @return*/public static synchronized Singleton getInstance() {// 延迟初始化,在首次调用该方法时才创建实例if (instance == null) {instance = new Singleton();}return instance;}/*** 其他业务方法*/public void doSomething() {System.out.println("其他业务方法...");}public static void main(String[] args) {// 使用单例模式获取实例Singleton singleton1 = Singleton.getInstance();Singleton singleton2 = Singleton.getInstance();// 验证是否是同一个实例if (singleton1 == singleton2) {System.out.println("相同的实例对象");} else {System.out.println("不同的实例对象");}}
}
在上面的示例中,Singleton
类的构造函数是私有的,确保其他类无法直接实例化该类。通过 getInstance()
方法获取唯一实例,使用了简单的同步机制来保证线程安全
。请注意,这种简单的同步机制虽然保证了线程安全,但在多线程环境下可能会有一些性能开销
。在实际开发中,可以考虑使用更高效的实现方式,比如基于静态内部类的单例模式
运行以上代码将看到输出结果表明 singleton1
和 singleton2
是同一个实例,证明单例模式确保了类只有一个唯一的实例
使用场景
以下为单例模式的使用场景,读取系统配置中的两个设置。在项目启动后通过调用获取实例方法获取系统的配置,使得在项目的任何地方都会读取到相同的配置。
需要知道的是,在使用此设置时通过SystemConfig.getInstance() 获取项目配置信息,而非通过在类中增加@configuration注解获取到配置实例,可以提升项目的启动速度
package com.zhouquan.entity;import lombok.Data;/*** @author ZhouQuan* @desciption 单例模式的使用场景* @date 2023/7/23 10:17*/
@Data
public class SystemConfig {private static SystemConfig instance = null;/*** 是否启动定时*/private boolean enableTime;/*** 是否重试数据同步*/private boolean retrySync;private SystemConfig() {}public static SystemConfig getInstance() {if (instance == null) {instance = new SystemConfig();}return instance;}
}
单例模式优缺点
优点:
-
唯一实例
:单例模式确保一个类只有一个实例存在,这样可以防止多次实例化,避免了资源浪费,同时也确保了对象的唯一性,方便对该实例进行全局访问 -
全局访问
:由于单例模式的实例在整个应用程序中是全局可访问的,因此可以在不同的模块和组件中共享实例,方便数据共享和通信 -
延迟实例化
:单例模式可以实现延迟实例化,即只在需要的时候才创建实例。这在某些情况下可以节省系统资源,提高系统的启动效率 -
避免竞态条件
:在多线程环境下,单例模式可以避免由于多个线程同时创建实例而引发的竞态条件(Race Condition),保证实例的唯一性和正确性
缺点:
-
难以扩展:由于单例模式限制了类只能有一个实例,因此扩展时可能会遇到一些困难。如果需要扩展单例类,可能需要修改原有的代码
-
单一职责原则问题:单例模式将实例的创建逻辑和实例的职责混合在一起,可能违反了单一职责原则。这样会使得单例类的代码较为复杂
-
对象生命周期问题:由于单例模式的实例在整个应用程序的生命周期中都存在,可能会导致对象长时间驻留在内存中,增加了内存使用
-
可测试性问题:由于单例模式在全局范围内访问实例,可能会导致依赖于单例实例的类难以进行单元测试
总体来说,单例模式在某些情况下非常有用,特别是需要确保全局唯一实例和避免资源浪费的场景。然而,在使用单例模式时需要慎重考虑,确保它不会导致代码的复杂性增加,并且不会影响系统的可扩展性和可测试性
2. 工厂模式(Factory Pattern)
工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种统一的接口来创建对象,而不需要暴露对象的创建逻辑。通过使用工厂模式,可以将对象的实例化过程封装在工厂类中,客户端只需要与工厂类进行交互,从而降低了代码的耦合性,增强了代码的可维护性和可扩展性
工厂模式有三种常见的变体:简单工厂模式、工厂方法模式和抽象工厂模式
说明
-
Product 是产品接口,定义了产品对象的通用行为 show()
-
ConcreteProductA 和 ConcreteProductB 分别是具体产品A和具体产品B,它们实现了 Product 接口,并提供了自己的具体实现
-
SimpleFactory 是简单工厂类,包含静态方法 createProduct() 来根据不同的参数创建具体的产品实例
-
Main 是客户端代码,通过调用 SimpleFactory 的静态方法来获取产品实例并使用产品的 show() 方法
+----------------------+| Product |+----------------------+| <<interface>> || show() |+----------------------+^|||+--------------------------+ +----------------------------+| | |+-----------------+ +----------------+ +----------------+|ConcreteProductA | | SimpleFactory | |ConcreteProductB|+-----------------+ +----------------+ +----------------+| show() | | createProduct()| | show() |+----------------+ +----------------+ +----------------+^||||+------------------+| ConcreteProductA |+------------------+| show() |+------------------+
2.1 简单工厂模式(Simple Factory Pattern)
简单工厂模式并不是标准的设计模式,它更像是一种编程习惯。在简单工厂模式中,我们创建一个工厂类,该工厂类根据不同的参数来创建不同的产品类实例
代码示例:
package com.zhouquan.entity.factory;/*** 产品接口*/
interface Product {/*** 商品类需要实现的方法*/void show();
}/*** 具体产品A*/
class ConcreteProductA implements Product {@Overridepublic void show() {System.out.println("具体产品A");}
}/*** 具体产品B*/
class ConcreteProductB implements Product {@Overridepublic void show() {System.out.println("具体产品B");}
}/*** 产品枚举类*/
enum ProductEnums {/*** 产品A*/CONCRETE_PRODUCT_A,/*** 产品B*/CONCRETE_PRODUCT_B
}/*** 简单工厂类*/
class SimpleFactory {public static Product createProduct(ProductEnums productEnums) {if (productEnums.equals(ProductEnums.CONCRETE_PRODUCT_A)) {return new ConcreteProductA();} else if (productEnums.equals(ProductEnums.CONCRETE_PRODUCT_B)) {return new ConcreteProductB();} else {throw new IllegalArgumentException("无效产品类型");}}
}/*** @author ZhouQuan* @description 简单工厂模式(Simple Factory Pattern)* @date 2023-07-23 10:36**/
public class SimpleFactoryPattern {public static void main(String[] args) {Product productA = SimpleFactory.createProduct(ProductEnums.CONCRETE_PRODUCT_A);Product productB = SimpleFactory.createProduct(ProductEnums.CONCRETE_PRODUCT_B);productA.show();productB.show();}
}
2.2 工厂方法模式(Factory Method Pattern)
工厂方法模式将每个具体产品的创建逻辑委托给各自的工厂类。每个具体产品对应一个工厂类,通过实现工厂接口来创建具体产品
代码示例:
package com.zhouquan.entity.factory;/*** 产品接口*/
interface Product {/*** 商品类需要实现的方法*/void show();
}/*** 具体产品A*/
class ConcreteProductA implements Product {@Overridepublic void show() {System.out.println("具体产品A");}
}/*** 具体产品B*/
class ConcreteProductB implements Product {@Overridepublic void show() {System.out.println("具体产品B");}
}/*** 工厂接口*/
interface Factory {Product createProduct();
}/*** 具体工厂A*/
class ConcreteFactoryA implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductA();}
}/*** 具体工厂B*/
class ConcreteFactoryB implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductB();}
}/*** @author ZhouQuan* @desciption 工厂方法模式(Factory Method Pattern)* @date 2023/7/23 11:35*/
public class FactoryMethodPattern {public static void main(String[] args) {Factory factoryA = new ConcreteFactoryA();Factory factoryB = new ConcreteFactoryB();Product productA = factoryA.createProduct();Product productB = factoryB.createProduct();productA.show();productB.show();}
}
2.3 抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式提供一个接口,用于创建一系列相关或相互依赖的产品对象。每个具体工厂实现该接口,用于创建一组产品对象
代码示例:
package com.zhouquan.entity.factory;/*** 产品接口*/
interface Product {/*** 商品类需要实现的方法*/void show();
}/*** 具体产品A*/
class ConcreteProductA implements Product {@Overridepublic void show() {System.out.println("具体产品A");}
}/*** 具体产品B*/
class ConcreteProductB implements Product {@Overridepublic void show() {System.out.println("具体产品B");}
}/*** 工厂接口*/
interface Factory {Product createProduct();
}/*** 具体工厂A*/
class ConcreteFactoryA implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductA();}
}/*** 具体工厂B*/
class ConcreteFactoryB implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductB();}
}/*** @author ZhouQuan* @desciption 工厂方法模式(Factory Method Pattern)* @date 2023/7/23 11:35*/
public class FactoryMethodPattern {public static void main(String[] args) {Factory factoryA = new ConcreteFactoryA();Factory factoryB = new ConcreteFactoryB();Product productA = factoryA.createProduct();Product productB = factoryB.createProduct();productA.show();productB.show();}
}
3. 观察者模式(Observer Pattern)
观察者模式(Observer Pattern)是一种行为型设计模式
,用于定义一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖于它的对象都能够得到通知并自动更新
观察者模式主要角色
-
Subject(主题):也称为
被观察者或可观察者
,它是一个具有状态的对象,当它的状态发生变化时,会通知所有注册过的观察者 -
Observer(观察者):观察者关注主题的状态变化,在主题发生变化时,接收到通知并进行相应的更新操作
观察者模式的优点在于解耦了主题和观察者
,使得它们可以相互独立地变化,同时也增加了系统的灵活性和扩展性
观察者模式要素
-
Subject(主题)接口:定义了添加、删除和通知观察者的方法
-
ConcreteSubject(具体主题)类:实现了Subject接口,维护了观察者列表,并在状态发生变化时通知观察者
-
Observer(观察者)接口:定义了接收通知并作出相应更新的方法
-
ConcreteObserver(具体观察者)类:实现了Observer接口,在接收到主题通知时执行相应的操作
代码示例
package com.zhouquan.entity.observer;import java.util.ArrayList;
import java.util.List;/*** 主题接口*/
interface Subject {/*** 注册观察者*/void registerObserver(Observer observer);/*** 移除观察者*/void removeObserver(Observer observer);/*** 通知所有已注册的观察者*/void notifyObservers();}/*** 具体主题类* 负责维护观察者列表和状态,并在状态发生变化时通知所有注册的观察者*/
class ConcreteSubject implements Subject {/*** 观察者对象列表*/private List<Observer> observers = new ArrayList<>();/*** 观察者状态*/private String state;@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(state);}}/*** 设置状态,并通知观察者** @param state*/public void setState(String state) {this.state = state;notifyObservers();}
}/*** 观察者接口*/
interface Observer {void update(String state);
}/*** 具体观察者类* 实现了Observer接口,在接收到主题通知时执行相应的操作*/
class ConcreteObserver implements Observer {private String name;public ConcreteObserver(String name) {this.name = name;}@Overridepublic void update(String state) {System.out.println(name + "收到更新,新状态为:" + state);}
}/*** @author ZhouQuan* @description 观察者模式* @date 2023-07-23 21:00**/
public class ObserverPattern {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();Observer observer1 = new ConcreteObserver("Observer1");Observer observer2 = new ConcreteObserver("Observer2");subject.registerObserver(observer1);subject.registerObserver(observer2);subject.setState("State 1");subject.removeObserver(observer1);subject.setState("State 2");}
}
在main方法代码中创建了一个具体主题对象subject
和两个具体观察者对象observer1
和observer2
。首先将两个观察者注册到主题上,然后通过setState()
方法改变主题的状态,观察者会收到通知并更新。之后从主题中移除一个观察者,再次改变主题的状态,只有一个观察者会收到通知。
这样,观察者模式就成功地实现了一对多
的依赖关系,当主题状态发生变化时,所有观察者都能够得到通知并作出相应的更新
4. 策略模式(Strategy Pattern)
策略模式(Strategy Pattern)是一种行为型设计模式
,它定义了一族算法,并将每个算法封装起来,使它们之间可以互相替换,从而使客户端代码与具体算法的实现解耦
策略模式的主要目的是让算法的变化独立于使用算法的客户端
。这样,客户端代码就可以根据需要选择不同的算法,而不需要修改其代码,从而实现了算法的动态切换
策略模式的核心结构主要角色
-
Context(环境):环境类,用于持有一个策略对象,并在需要时调用策略对象的方法。它通常代表客户端使用的
接口
-
Strategy(策略):策略接口,定义了
算法的公共接口
。具体的策略类实现了策略接口,提供不同的算法实现
。 -
ConcreteStrategy(具体策略):
具体策略类
,实现了策略接口定义的算法。在客户端选择不同的策略时,使用不同的具体策略类
+-------------------+| Strategy |+-------------------+| + doOperation() |+-------------------+^|| implements|+------------------------+ +------------------------+| ConcreteStrategyA | | ConcreteStrategyB |+------------------------+ +------------------------+| + doOperation() | | + doOperation() |+------------------------+ +------------------------+^|| uses|+------------+| Context |+------------+| - strategy |+------------+^|| depends on|+--------------+| Main |+--------------+
策略模式的优点
策略模式的优点在于可以有效地避免使用大量的条件判断语句,将算法的选择和使用与客户端的代码解耦,提高代码的灵活性和可维护性
代码策略模式示例
package com.zhouquan.entity.strategy;/*** IP策略接口*/
interface IpStrategy {/*** 校验ip类型* 判断是IPv4还是IPv6** @param ip ip字符串* @return string 返回校验结果*/String checkIpType(String ip);
}/*** 具体策略 IPv4*/
class IPv4Strategy implements IpStrategy {@Overridepublic String checkIpType(String ip) {return "使用IPv4策略,结果为:" + ip;}
}/*** 具体策略 IPv6*/
class IPv6Strategy implements IpStrategy {@Overridepublic String checkIpType(String ip) {return "使用IPv6策略,结果为:" + ip;}
}/*** 环境类*/
class IpContext {private IpStrategy ipStrategy;public IpContext(IpStrategy ipStrategy) {this.ipStrategy = ipStrategy;}public String checkIpType(String ipAddress) {return ipStrategy.checkIpType(ipAddress);}
}/*** @author ZhouQuan* @description 策略模式(Strategy Pattern)* @date 2023-07-23 21:27**/
public class StrategyPattern {public static void main(String[] args) {String ipv4Address = "192.168.1.1";String ipv6Address = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";/*** 策略模式的主要目的是让算法的变化独立于使用算法的代码* 通过实例化不同的`Context`对象,并传入不同的具体策略类可以根据需要选择不同的算法,而不* 需要修改其代码,从而实现了算法的动态切换*/IpContext ipv4Context = new IpContext(new IPv4Strategy());IpContext ipv6Context = new IpContext(new IPv6Strategy());String ipv4Result = ipv4Context.checkIpType(ipv4Address);String ipv6Result = ipv6Context.checkIpType(ipv6Address);System.out.println("IPv4 地址校验:" + ipv4Result);System.out.println("IPv6 地址校验:" + ipv6Result);}
}
在上述示例中,我们创建了一个策略接口IpStrategy
,并实现了两种具体策略类IPv4Strategy
和IPv6Strategy
,它们分别执行不同的算法来校验ip类型IpContext
类是环境类,持有一个策略对象,并在需要时调用策略对象的方法
5. 适配器模式(Adapter Pattern)
适配器模式(Adapter Pattern)是一种结构型设计模式
,它允许将一个类的接口转换成客户端所期望的另一个接口,从而使原本不兼容的类能够一起工作。适配器模式主要用于解决现有系统之间接口不兼容的问题,同时也能够将已有类和新类进行协调工作
适配器模式主要角色
-
目标接口(Target):客户端期望的接口,它
定义了客户端可以调用的方法
-
适配器(Adapter):
适配器是将原有接口转换成目标接口的中间桥梁
。它实现了目标接口,并持有原有接口的引用,将客户端请求转发给原有接口
-
被适配者(Adaptee):被适配者是已有的类,它的接口和客户端期望的目标接口不兼容
适配器模式的优点在于它可以使不兼容的类能够协调工作,同时也提高了代码的复用性和灵活性
适配器模式代码示例
package com.zhouquan.entity.adapter;/*** 目标接口*/
interface MediaPlayer {/*** 视频播放方法** @param audioType 视频类型* @param fileName 文件名*/void play(AudioType audioType, String fileName);
}/*** 视频类型的枚举类*/
enum AudioType {MP4,VLC
}/*** 被适配者:AdvancedMediaPlayer接口*/
interface AdvancedMediaPlayer {/*** vlc格式播放** @param fileName*/void playVlc(String fileName);/*** mp4格式播放** @param fileName*/void playMp4(String fileName);
}/*** 具体被适配者:VlcPlayer类*/
class VlcPlayer implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {System.out.println("播放vlc格式.文件名: " + fileName);}@Overridepublic void playMp4(String fileName) {// 空实现,不处理}
}/*** 具体被适配者:Mp4Player类*/
class Mp4Player implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {// 空实现,不处理}@Overridepublic void playMp4(String fileName) {System.out.println("播放mp4格式.文件名: " + fileName);}
}/*** 适配器类:MediaPlayerAdapter*/
class MediaPlayerAdapter implements MediaPlayer {private AdvancedMediaPlayer advancedMediaPlayer;public MediaPlayerAdapter(AudioType audioType) {if (audioType == AudioType.VLC) {advancedMediaPlayer = new VlcPlayer();} else if (audioType == AudioType.MP4) {advancedMediaPlayer = new Mp4Player();}}@Overridepublic void play(AudioType audioType, String fileName) {if (audioType == AudioType.VLC) {advancedMediaPlayer.playVlc(fileName);} else if (audioType == AudioType.MP4) {advancedMediaPlayer.playMp4(fileName);}}
}/*** @author ZhouQuan* @description 适配器模式(Adapter Pattern)* @date 2023-07-23 22:03**/
public class AdapterPattern {public static void main(String[] args) {MediaPlayer mediaPlayer = new MediaPlayerAdapter(AudioType.MP4);mediaPlayer.play(AudioType.MP4, "蔡徐坤打篮球.mp4");}
}
在上述示例中实现了一个简单的适配器模式。MediaPlayer
是目标接口,AdvancedMediaPlayer
是已有的不兼容接口。VlcPlayer
和 Mp4Player
是具体的被适配者。MediaPlayerAdapter
是适配器类,它实现了目标接口,并持有一个 AdvancedMediaPlayer
引用,将客户端请求转发给具体被适配者
6. 装饰器模式(Decorator Pattern)
装饰器模式(Decorator Pattern)是一种结构型设计模式
,允许你在不改变对象接口的情况下,动态地添加功能到对象上
。它通过创建一个装饰器类来包装原始对象,从而为原始对象添加新的行为。这样可以使代码更加灵活,同时符合开放封闭原则(Open/Closed Principle),即对扩展开放,对修改关闭
装饰器模式主要角色
-
Component(抽象构件):定义了一个抽象接口,可以是接口或抽象类,被装饰的对象和装饰器都实现这个接口
-
ConcreteComponent(具体构件):实现了抽象构件接口,是被装饰的原始对象
-
Decorator(装饰器):也是抽象类或接口,持有一个对抽象构件的引用,并定义与抽象构件一致的接口
-
ConcreteDecorator(具体装饰器):继承自装饰器类,实现了装饰器接口,负责在具体构件上添加新的功能
代码示例
下面用一个简单的 Java 示例来说明装饰器模式的用法。以咖啡店为例,有不同种类的咖啡(具体构件),可以在咖啡中添加额外的调料(具体装饰器)
package com.zhouquan.entity.decorator;/*** Component(抽象构件)*/
interface Coffee {double getCost();String getDescription();
}/*** ConcreteComponent(具体构件)*/
class SimpleCoffee implements Coffee {@Overridepublic double getCost() {return 10.0;}@Overridepublic String getDescription() {return "一杯原始咖啡 ";}
}/*** Decorator(装饰器)*/
abstract class CoffeeDecorator implements Coffee {protected Coffee coffee;public CoffeeDecorator(Coffee coffee) {this.coffee = coffee;}
}/*** ConcreteDecorator(具体装饰器)*/
class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}@Overridepublic double getCost() {return coffee.getCost() + 5.0;}@Overridepublic String getDescription() {return coffee.getDescription() + ",加牛奶 ";}
}/*** ConcreteDecorator(具体装饰器)*/
class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) {super(coffee);}@Overridepublic double getCost() {return coffee.getCost() + 2.0;}@Overridepublic String getDescription() {return coffee.getDescription() + ",加糖 ";}
}/*** @author ZhouQuan* @description 装饰器模式(Decorator Pattern)* @date 2023-07-23 22:33**/
public class DecoratorPattern {public static void main(String[] args) {// 原始咖啡Coffee simpleCoffee = new SimpleCoffee();// 一杯原始咖啡 10.0System.out.println(simpleCoffee.getDescription() + simpleCoffee.getCost());// 使用装饰器添加调料Coffee milkCoffee = new MilkDecorator(simpleCoffee);Coffee sugarMilkCoffee = new SugarDecorator(milkCoffee);//一杯原始咖啡 ,加牛奶 ,加糖 17.0System.out.println(sugarMilkCoffee.getDescription() + sugarMilkCoffee.getCost());}
}
通过装饰器模式可以轻松地给咖啡添加不同的调料,而不需要修改原始的咖啡类。这使得代码更加灵活,并且可以方便地增加新的装饰器类来拓展功能
7. 命令模式(Command Pattern)
命令模式(Command Pattern)是一种行为型设计模式
,用于将请求(命令)封装成一个对象,从而允许你使用不同的请求、队列或者日志来参数化其他对象。它可以将请求的发送者(Invoker)和接收者(Receiver)解耦,让发送者不需要知道接收者的具体处理过程,只需通过命令对象来执行请求
命令模式主要角色
-
Command(命令):声明执行操作的接口,通常包含一个
execute
方法。 -
ConcreteCommand(具体命令):实现Command接口,在
execute
方法中封装了具体的操作,同时持有一个接收者对象。 -
Receiver(接收者):负责执行具体的操作。
-
Invoker(调用者):负责调用命令对象的
execute
方法来执行请求。
代码示例
假设我们有一个遥控器,上面有一些按钮,每个按钮可以控制不同的电器设备(例如电灯、音响等)
package com.zhouquan;/*** Command(命令)*/
interface Command {void execute();
}/*** ConcreteCommand(具体命令) - 电灯开启命令*/
class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOn();}
}/*** ConcreteCommand(具体命令) - 电灯关闭命令*/
class LightOffCommand implements Command {private Light light;public LightOffCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOff();}
}/*** Receiver(接收者) - 电灯*/
class Light {public void turnOn() {System.out.println("开灯");}public void turnOff() {System.out.println("关灯");}
}/*** Invoker(调用者) - 遥控器*/
class RemoteControl {private Command command;public void setCommand(Command command) {this.command = command;}public void pressButton() {command.execute();}
}/*** @author ZhouQuan* @description 命令模式(Command Pattern)* @date 2023-07-23 22:45**/
public class CommandPattern {public static void main(String[] args) {RemoteControl remoteControl = new RemoteControl();Light light = new Light();Command lightOnCommand = new LightOnCommand(light);Command lightOffCommand = new LightOffCommand(light);remoteControl.setCommand(lightOnCommand);remoteControl.pressButton();remoteControl.setCommand(lightOffCommand);remoteControl.pressButton();}
}
通过命令模式将请求(控制电灯)封装成了具体的命令对象,使得发送者(遥控器)和接收者(电灯)解耦,从而实现了更灵活和可扩展的控制方式