Java设计模式—软件设计原则和七大常用的设计模式

前言

设计模式是软件开发中常见问题的解决方案,它们是经过验证的并且经常被重复使用的设计模板。设计模式提供了一套通用的解决方案,帮助开发人员构建高质量、可维护和可扩展的代码。设计模式并不是特定于某种编程语言,而是面向对象编程范式的通用原则

一. 设计模式的类型

创建型模式(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):在不改变数据结构的前提下,增加新的操作,即将处理从数据结构分离出来

最常用的七种设计模式如下:

  1. 单例模式(Singleton Pattern)
  2. 工厂模式(Factory Pattern)
  3. 观察者模式(Observer Pattern)
  4. 策略模式(Strategy Pattern)
  5. 适配器模式(Adapter Pattern)
  6. 装饰器模式(Decorator Pattern)
  7. 命令模式(Command Pattern)

二. 软件设计七大原则

软件设计七大原则,也称为SOLID原则,是一组面向对象设计的指导原则,旨在帮助开发人员编写可维护、可扩展和易于理解的代码。这些原则和设计模式密切相关,它们共同为面向对象编程提供了一套综合的指导方针。SOLID 是一组面向对象编程和设计原则的首字母缩略词,即下列前五种设计原则中的首字母

以下是SOLID原则的简要介绍和与设计模式的关系:

  1. 单一职责原则(Single Responsibility Principle)
    一个类应该只有一个引起变化的原因。这意味着一个类应该只负责一项职责。遵循单一职责原则可以提高类的内聚性和可维护性

    关系设计模式:单例模式、工厂模式、观察者模式等,这些设计模式都帮助实现单一职责原则,将不同的功能拆分到不同的类中。

  2. 开放封闭原则(Open/Closed Principle)
    软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。这意味着应该通过扩展现有的代码来引入新功能,而不是直接修改现有的代码

    关系设计模式:策略模式、装饰器模式、观察者模式等,这些设计模式支持开放封闭原则,通过定义接口、抽象类和组合来实现可扩展性

  3. 里氏替换原则(Liskov Substitution Principle)
    子类对象应该能够替换其基类对象,而不影响程序的正确性。即在不改变程序正确性的前提下,派生类可以扩展基类的功能

    关系设计模式:工厂模式、模板方法模式等,这些设计模式利用了子类替换基类的特性,让代码更加灵活和可扩展

  4. 接口隔离原则(Interface Segregation Principle)
    客户端不应该强迫依赖于它们不使用的接口。一个类不应该依赖于它不需要的接口

    关系设计模式:适配器模式、策略模式等,这些设计模式帮助实现接口隔离原则,将大接口拆分成多个小接口,让类只依赖于需要的接口

  5. 依赖倒置原则(Dependency Inversion Principle)
    高层模块不应该依赖于低层模块,而是应该依赖于抽象。抽象不应该依赖于具体实现细节,而是具体实现应该依赖于抽象

    关系设计模式:依赖注入、工厂模式等,这些设计模式遵循依赖倒置原则,通过依赖抽象而不是具体实现来降低模块之间的耦合

  6. 合成复用原则(Composition/Aggregation Reuse Principle)
    优先使用对象组合或聚合,而不是继承来达到代码复用的目的。通过组合关系,可以更灵活地增加、删除或替换组件

    关系设计模式:装饰器模式、组合模式等,这些设计模式强调对象组合或聚合,而不是继承来实现代码复用

  7. 迪米特法则(Law of Demeter,最少知识原则)
    一个对象应该对其他对象有尽可能少的了解。即一个类应该尽量减少与其他类之间的交互,尽量降低耦合性

    关系设计模式:外观模式、中介者模式等,这些设计模式帮助减少对象之间的直接交互,通过引入中间类来降低类之间的耦合度

软件设计原则的目的:

降低对象之间的耦合性和复杂度,提升对象的内聚性,增加程序的可复用性、可扩展性和可维护性

三. 设计模式详解

1. 单例模式(Singleton Pattern)

单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。这样可以避免多次实例化相同类的对象,节省内存资源,并确保在整个应用程序中只有一个共享的实例被使用

详细介绍

在单例模式中,有几个重要的要点需要考虑:

  1. 私有的构造函数: 为了防止在外部类中直接实例化对象,单例类的构造函数应该设为私有的,这样其他类就无法通过 new 操作符创建该类的对象

  2. 静态成员变量: 单例类需要一个静态成员变量来保存唯一实例的引用,确保全局唯一性

  3. 静态获取方法: 单例类应该提供一个静态的、公共的方法来获取该类的唯一实例。这个方法通常命名为 getInstance()

  4. 延迟初始化: 在首次调用 getInstance() 方法时才创建实例,而不是在类加载时就创建实例,这样可以实现延迟初始化,提高性能

  5. 线程安全: 需要考虑多线程环境下的并发访问问题。可以使用同步机制来保证线程安全,但需要注意性能开销

代码示例

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() 方法获取唯一实例,使用了简单的同步机制来保证线程安全。请注意,这种简单的同步机制虽然保证了线程安全,但在多线程环境下可能会有一些性能开销。在实际开发中,可以考虑使用更高效的实现方式,比如基于静态内部类的单例模式

运行以上代码将看到输出结果表明 singleton1singleton2 是同一个实例,证明单例模式确保了类只有一个唯一的实例

使用场景

以下为单例模式的使用场景,读取系统配置中的两个设置。在项目启动后通过调用获取实例方法获取系统的配置,使得在项目的任何地方都会读取到相同的配置。
需要知道的是,在使用此设置时通过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;}
}

单例模式优缺点

优点:

  1. 唯一实例:单例模式确保一个类只有一个实例存在,这样可以防止多次实例化,避免了资源浪费,同时也确保了对象的唯一性,方便对该实例进行全局访问

  2. 全局访问:由于单例模式的实例在整个应用程序中是全局可访问的,因此可以在不同的模块和组件中共享实例,方便数据共享和通信

  3. 延迟实例化:单例模式可以实现延迟实例化,即只在需要的时候才创建实例。这在某些情况下可以节省系统资源,提高系统的启动效率

  4. 避免竞态条件:在多线程环境下,单例模式可以避免由于多个线程同时创建实例而引发的竞态条件(Race Condition),保证实例的唯一性和正确性

缺点:

  1. 难以扩展:由于单例模式限制了类只能有一个实例,因此扩展时可能会遇到一些困难。如果需要扩展单例类,可能需要修改原有的代码

  2. 单一职责原则问题:单例模式将实例的创建逻辑和实例的职责混合在一起,可能违反了单一职责原则。这样会使得单例类的代码较为复杂

  3. 对象生命周期问题:由于单例模式的实例在整个应用程序的生命周期中都存在,可能会导致对象长时间驻留在内存中,增加了内存使用

  4. 可测试性问题:由于单例模式在全局范围内访问实例,可能会导致依赖于单例实例的类难以进行单元测试

总体来说,单例模式在某些情况下非常有用,特别是需要确保全局唯一实例和避免资源浪费的场景。然而,在使用单例模式时需要慎重考虑,确保它不会导致代码的复杂性增加,并且不会影响系统的可扩展性和可测试性

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)是一种行为型设计模式,用于定义一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖于它的对象都能够得到通知并自动更新

观察者模式主要角色

  1. Subject(主题):也称为被观察者或可观察者,它是一个具有状态的对象,当它的状态发生变化时,会通知所有注册过的观察者

  2. Observer(观察者):观察者关注主题的状态变化,在主题发生变化时,接收到通知并进行相应的更新操作

观察者模式的优点在于解耦了主题和观察者,使得它们可以相互独立地变化,同时也增加了系统的灵活性和扩展性

观察者模式要素

  1. Subject(主题)接口:定义了添加、删除和通知观察者的方法

  2. ConcreteSubject(具体主题)类:实现了Subject接口,维护了观察者列表,并在状态发生变化时通知观察者

  3. Observer(观察者)接口:定义了接收通知并作出相应更新的方法

  4. 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和两个具体观察者对象observer1observer2。首先将两个观察者注册到主题上,然后通过setState()方法改变主题的状态,观察者会收到通知并更新。之后从主题中移除一个观察者,再次改变主题的状态,只有一个观察者会收到通知。
这样,观察者模式就成功地实现了一对多的依赖关系,当主题状态发生变化时,所有观察者都能够得到通知并作出相应的更新

4. 策略模式(Strategy Pattern)

策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一族算法,并将每个算法封装起来,使它们之间可以互相替换,从而使客户端代码与具体算法的实现解耦

策略模式的主要目的是让算法的变化独立于使用算法的客户端。这样,客户端代码就可以根据需要选择不同的算法,而不需要修改其代码,从而实现了算法的动态切换

策略模式的核心结构主要角色

  1. Context(环境):环境类,用于持有一个策略对象,并在需要时调用策略对象的方法。它通常代表客户端使用的接口

  2. Strategy(策略):策略接口,定义了算法的公共接口。具体的策略类实现了策略接口,提供不同的算法实现

  3. 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,并实现了两种具体策略类IPv4StrategyIPv6Strategy,它们分别执行不同的算法来校验ip类型IpContext类是环境类,持有一个策略对象,并在需要时调用策略对象的方法

5. 适配器模式(Adapter Pattern)

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将一个类的接口转换成客户端所期望的另一个接口,从而使原本不兼容的类能够一起工作。适配器模式主要用于解决现有系统之间接口不兼容的问题,同时也能够将已有类和新类进行协调工作

适配器模式主要角色

  1. 目标接口(Target):客户端期望的接口,它定义了客户端可以调用的方法

  2. 适配器(Adapter):适配器是将原有接口转换成目标接口的中间桥梁。它实现了目标接口,并持有原有接口的引用,将客户端请求转发给原有接口

  3. 被适配者(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 是已有的不兼容接口。VlcPlayerMp4Player 是具体的被适配者。MediaPlayerAdapter 是适配器类,它实现了目标接口,并持有一个 AdvancedMediaPlayer 引用,将客户端请求转发给具体被适配者

6. 装饰器模式(Decorator Pattern)

装饰器模式(Decorator Pattern)是一种结构型设计模式允许你在不改变对象接口的情况下,动态地添加功能到对象上。它通过创建一个装饰器类来包装原始对象,从而为原始对象添加新的行为。这样可以使代码更加灵活,同时符合开放封闭原则(Open/Closed Principle),即对扩展开放,对修改关闭

装饰器模式主要角色

  1. Component(抽象构件):定义了一个抽象接口,可以是接口或抽象类,被装饰的对象和装饰器都实现这个接口

  2. ConcreteComponent(具体构件):实现了抽象构件接口,是被装饰的原始对象

  3. Decorator(装饰器):也是抽象类或接口,持有一个对抽象构件的引用,并定义与抽象构件一致的接口

  4. 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)解耦,让发送者不需要知道接收者的具体处理过程,只需通过命令对象来执行请求

命令模式主要角色

  1. Command(命令):声明执行操作的接口,通常包含一个execute方法。

  2. ConcreteCommand(具体命令):实现Command接口,在execute方法中封装了具体的操作,同时持有一个接收者对象。

  3. Receiver(接收者):负责执行具体的操作。

  4. 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();}
}

通过命令模式将请求(控制电灯)封装成了具体的命令对象,使得发送者(遥控器)和接收者(电灯)解耦,从而实现了更灵活和可扩展的控制方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/6474.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习深度学习——随机梯度下降算法(及其优化)

在我们没有办法得到解析解的时候&#xff0c;我们可以用过梯度下降来进行优化&#xff0c;这种方法几乎可以所有深度学习模型。 关于优化的东西&#xff0c;我自己曾经研究过智能排班算法和优化&#xff0c;所以关于如何找局部最小值&#xff0c;以及如何跳出局部最小值的一些基…

RUST腐蚀基因种植

RUST腐蚀基因种植 试验地址:www.xiaocao.cloud RUST基因: RUST基因计算器&#xff0c;腐蚀基因计算器&#xff0c;前后端分离架构&#xff0c;前端目录/resouce/ui/rust&#xff0c;欢迎大佬评价&#xff0c;

无涯教程-HTML Event Reference

当用户访问您的网站时,他们会执行诸如单击文本和图像以及给定的链接,将鼠标悬停在事物上等操作。这些都是JavaScript称为事件的Example。 我们可以用Javascript或vbscript编写事件处理程序,并可以将这些事件处理程序指定为事件标签属性的值。 HTML 4.01规范定义了19个事件属性…

算法笔记(java)——回溯篇

回溯算法解决问题最有规律性&#xff0c;借用一下卡哥的图&#xff1a; 只要遇到上述问题就可以考虑使用回溯&#xff0c;回溯法的效率并不高&#xff0c;是一种暴力解法&#xff0c;其代码是嵌套在for循环中的递归&#xff0c;用来解决暴力算法解决不了的问题&#xff0c;即…

Tensorflow无人车使用移动端的SSD(单发多框检测)来识别物体及Graph的认识

环境是树莓派3B&#xff0c;当然这里安装tensorflow并不是一定要在树莓派环境&#xff0c;只需要是ARM架构就行&#xff0c;也就是目前市场上绝大部分的嵌入式系统都是用这套精简指令集。 在电脑端的检测&#xff0c;有兴趣的可以查阅SSD(Single Shot MultiBox Detector)系列&a…

19 QListWidget控件

Tips: 对于列表式数据可以使用QStringList进行左移一块输入。 代码&#xff1a; //listWidget使用 // QListWidgetItem * item new QListWidgetItem("锄禾日当午"); // QListWidgetItem * item2 new QListWidgetItem("汗滴禾下土"); // ui->…

十、正则表达式详解:掌握强大的文本处理工具(二)

文章目录 &#x1f340;多字符匹配&#x1f340;匹配规则的代替&#x1f340;特殊的匹配&#x1f340;特殊的匹配plus&#x1f340;总结 &#x1f340;多字符匹配 星号&#xff08;*&#xff09;&#xff1a;匹配0个或者多个字符 import retext 111-222-333 result re.matc…

苹果的Apple GPT要来了?

据外媒消息&#xff0c;苹果正在内部开发类 ChatGPT 的产品&#xff0c;与微软、OpenAI、谷歌、Meta 等科技巨头在生成式 AI 赛道展开竞争。该消息使得苹果股价上涨了 2%。据苹果工程师透露&#xff0c;苹果在内部构建了代号为“Ajax”的大语言模型开发框架&#xff0c;并构建了…

Unity自定义后处理——Bloom效果

大家好&#xff0c;我是阿赵。   继续介绍屏幕后处理效果&#xff0c;这一期讲一下Bloom效果。 一、Bloom效果介绍 还是拿这个模型作为背景。 Bloom效果&#xff0c;就是一种全屏泛光的效果&#xff0c;让模型和特效有一种真的在发光的感觉。 根据参数不一样&#xff0c;可…

Packet Tracer – 实施静态 NAT 和动态 NAT

Packet Tracer – 实施静态 NAT 和动态 NAT 拓扑图 目标 第 1 部分&#xff1a;利用 PAT 配置动态 NAT 第 2 部分&#xff1a;配置静态 NAT 第 3 部分&#xff1a;验证 NAT 实施 第 1 部分&#xff1a; 利用 PAT 配置动态 NAT 步骤 1&#xff1a; 配置允许用于 NAT …

【基于CentOS 7 的iscsi服务】

目录 一、概述 1.简述 2.作用 3. iscsi 4.相关名称 二、使用步骤 - 构建iscsi服务 1.使用targetcli工具进入到iscsi服务器端管理界面 2.实现步骤 2.1 服务器端 2.2 客户端 2.2.1 安装软件 2.2.2 在认证文件中生成iqn编号 2.2.3 开启客户端服务 2.2.4 查找可用的i…

Django中,对于GET /favicon.ico请求的操作

当浏览器请求网页时&#xff0c;通常会自动请求网站根目录下的/favicon.ico文件&#xff0c;该文件是用于网站图标的。在Django中&#xff0c;对于GET /favicon.ico请求的操作过程如下&#xff1a; Django的URL分发器&#xff08;URL dispatcher&#xff09;接收到请求&#xf…

AJAX-day03-AJAX进阶

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 同步代码和异步代码 回调函数地狱 Promise - 链式调用 Promise 链式应用 async函数和await async函…

Stable Diffusion入门笔记(自用)

学习视频&#xff1a;20分钟搞懂Prompt与参数设置&#xff0c;你的AI绘画“咒语”学明白了吗&#xff1f; | 零基础入门Stable Diffusion保姆级新手教程 | Prompt关键词教学_哔哩哔哩_bilibili 1.图片提示词模板 2.权重&#xff08;提示词&#xff09; 无数字 (flower)//花的…

MQTT网关 5G物联网网关 PLC控制工业网关

MQTT网关&#xff0c;两个以上的节点之间通信的新型网关&#xff0c;网络节点之间通过互连来实现双向通信。支持PLC协议转MQTT&#xff0c;实现plc数据采集上云&#xff0c;物联网云平台对接&#xff0c;广泛应用于工业自动化plc远程监测控制。 计讯物联5G MQTT物联网网关TG463…

如何解决 Git 合并冲突

在遇到合并冲突时&#xff0c;请不要惊慌。通过一些娴熟的技巧协商&#xff0c;你可以解决任何冲突。 假设你和我正在共同编辑同一个名称为 index.html 的文件。我对文件进行了修改&#xff0c;进行了提交&#xff0c;并将更改推送到 Git 远程仓库。你也对同一个文件进行了修改…

酷雷曼无人机技能培训考试圆满举办

2023年7月18日、19日&#xff0c;以“向云端起航&#xff0c;让技术落地”为主题的酷雷曼无人机技能提升培训会在酷雷曼北京运营中心隆重举行&#xff0c;来自全国各地的众多合作商参加了本次培训&#xff0c;通过系统、全面的学习成功取得了专业无人机飞行员执照&#xff0c;为…

BEVDet 论文解读

BEVDet: High-Performance Multi-Camera 3D Object Detection in Bird-Eye-View 作者单位 PhiGent Robotics 目的 2D 的视觉感知在过去的几年里有了急速的发展&#xff0c;涌现出一些优秀的范式工作&#xff0c;这些工作有较高的性能&#xff0c;可扩展性&#xff0c;以及多…

【目标检测】epoch、、batch、、batch_size理解

1 epoch 当一个完整的数据集通过神经网络一次并且返回一次的过程称为一个epoch。 然而&#xff0c;当一个epoch对于计算机太过庞大时&#xff0c;就需要把它分成多个小块。 2 batch 在不能将数据一次性通过神经网络的适合&#xff0c;就需要将数据集分成几个batch。 3 batch…

【数学建模】--典型相关分析

典型相关分析&#xff08;Canonical Correlation analysis&#xff09;研究两组变量&#xff08;每组变量中都可能有多个指标&#xff09;之间相关关系的一种多元统计方法。它能够揭示出两组变量之间的内在联系。 例子&#xff1a; 典型相关分析定义&#xff1a; 列题分析&…