设计模式
2023/8/8 09:31:55
2023/8/8 09:32:03
Java 中常用的设计模式有 23 种,它们按照不同的目的和使用场景进行分类,主要分为以下几个类别:
创建型设计模式:
结构型设计模式:
行为型设计模式:
这些设计模式各自解决不同的问题,可以提高代码的可复用性、可维护性和可扩展性。开发人员可以根据实际需求选择适合的设计模式来设计和实现软件系统。
设计模式七大原则
2023/8/8 09:57:57
2023/8/8 09:58:09
设计模式七大原则(也称为SOLID原则)是一组指导面向对象设计的准则,旨在提高代码的可维护性、可扩展性和可重用性。这些原则是:
单一职责原则(Single Responsibility Principle,SRP): 一个类应该只有一个引起变化的原因。每个类应该只负责单一的职责或功能,这样可以提高类的内聚性。
开闭原则(Open-Closed Principle,OCP): 软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。通过抽象化和接口定义,使得新功能的增加不需要修改现有代码,只需要添加新的代码。
里氏替换原则(Liskov Substitution Principle,LSP): 子类型必须能够替换它们的基类型,而程序的行为不会受到影响。子类应该能够完全替代父类并符合预期的行为。
接口隔离原则(Interface Segregation Principle,ISP): 客户端不应该依赖于它们不需要使用的接口。将臃肿的接口拆分成更小、更具体的接口,以避免客户端依赖于无关的接口。
依赖倒置原则(Dependency Inversion Principle,DIP): 高层模块不应该依赖于低层模块,它们应该依赖于抽象。模块间的依赖关系应该通过抽象建立,而不是直接依赖于具体实现。
迪米特法则(Law of Demeter,LoD): 一个对象应该对其他对象有最少的了解。一个类应该只与其直接的成员进行交互,而不需要了解其他类的内部细节。
合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP): 尽量使用合成/聚合,而不是继承来实现代码复用。通过对象组合或聚合关系,可以灵活地构建更复杂的对象结构。
这些原则提供了指导设计的准则,帮助开发者编写高质量、可维护和可扩展的代码。遵循这些原则可以促进面向对象设计的良好实践,并减少代码耦合度,增加代码的灵活性和可重用性。
简述设计模式的分类
2023/8/8 09:59:51
2023/8/8 10:00:12
设计模式可以根据其目的和范围进行分类。根据目的,设计模式可以分为三个主要类别:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)和行为型模式(Behavioral Patterns)。下面对这三个类别进行简要描述:
创建型模式: 创建型模式关注对象的实例化过程,用于创建对象的方式和机制。它们帮助我们在不直接实例化对象的情况下创建对象,并提供了灵活和可扩展的创建对象的方法。常见的创建型模式有:工厂模式(Factory Pattern)、抽象工厂模式(Abstract Factory Pattern)、建造者模式(Builder Pattern)、原型模式(Prototype Pattern)和单例模式(Singleton Pattern)。
结构型模式: 结构型模式关注如何将类和对象组合成更大的结构,以形成更复杂的系统。结构型模式帮助我们实现类之间的关联关系,从而实现系统的组织和协作。常见的结构型模式有:适配器模式(Adapter Pattern)、装饰器模式(Decorator Pattern)、代理模式(Proxy Pattern)、桥接模式(Bridge Pattern)、组合模式(Composite Pattern)、享元模式(Flyweight Pattern)和外观模式(Facade Pattern)。
行为型模式: 行为型模式关注对象之间的通信和协作,以及如何在系统中分配责任和行为。行为型模式帮助我们设计对象之间的交互方式,使系统更灵活和可扩展。常见的行为型模式有:策略模式(Strategy Pattern)、模板方法模式(Template Method Pattern)、观察者模式(Observer Pattern)、迭代器模式(Iterator Pattern)、责任链模式(Chain of Responsibility Pattern)、命令模式(Command Pattern)、备忘录模式(Memento Pattern)、状态模式(State Pattern)、访问者模式(Visitor Pattern)、中介者模式(Mediator Pattern)和解释器模式(Interpreter Pattern)。
这些分类提供了一种组织和理解各种设计模式的方法,使开发者可以根据需要选择最适合的模式来解决问题,并提高软件系统的设计质量。不同的设计模式类别解决了不同的设计问题,并在特定的上下文中发挥作用。因此,了解这些分类对于学习和应用设计模式非常重要。
单例模式
2023/8/8 09:57:16
2023/8/8 09:57:35
单例模式(Singleton Pattern)是一种创建型设计模式,它的目的是确保一个类只有一个实例,并提供全局访问点。
在单例模式中,类的构造函数被定义为私有的,这样就无法通过常规的方式直接实例化对象。通过在类内部创建一个静态方法或静态变量,在第一次调用该方法时创建唯一的实例,并将其保存起来。以后每次调用这个方法时,都返回之前创建的唯一实例。
单例模式的主要特点如下:
- 确保一个类只有一个实例存在。
- 提供一个全局访问点,可以在整个应用程序中访问该实例。
- 惰性加载(Lazy Initialization):实例只在第一次使用时创建,避免资源浪费。
单例模式在许多场景中被广泛应用,例如以下情况:
- 当某个类的实例需要被多个客户端共享时,使用单例模式可以确保所有客户端都获取到相同的实例。
- 当实例化过程比较昂贵或复杂时,使用单例模式可以避免重复创建实例。
- 当多个线程需要共享同一个实例时,单例模式可以确保线程安全。
在 Java 中实现单例模式的一种常见方式是使用静态变量和静态方法:
public class Singleton {
private static Singleton instance;
// 私有构造函数,防止其他类直接实例化
private Singleton() {
}
// 全局访问点,创建唯一实例
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
以上代码中,通过将构造函数设为私有,确保无法在类外部直接实例化对象。getInstance() 方法负责创建唯一的实例并返回。第一次调用 getInstance() 方法时,会创建对象并将其赋给静态变量 instance。以后每次调用 getInstance() 方法时,都直接返回之前创建的唯一实例。
需要注意的是,单例模式可能会引起全局状态共享和单例滥用的问题,因此在使用时需要权衡考虑,并确保满足应用场景的需求。
2023/8/8 10:06:56
2023/8/8 10:07:15
饿汉式和懒汉式是两种常见的单例设计模式实现方式。
饿汉式(Eager Initialization): 在饿汉式中,单例对象在类加载时就被立即初始化并创建。这意味着无论是否需要使用该单例对象,它都会在应用程序启动时被创建。饿汉式的实现简单直接,线程安全,但可能会造成资源浪费,尤其当单例对象比较庞大时。
示例代码:
public class Singleton { private static final Singleton instance = new Singleton(); private Singleton() { // 私有化构造函数,防止外部实例化 } public static Singleton getInstance() { return instance; } }
懒汉式(Lazy Initialization): 在懒汉式中,单例对象在第一次访问时才会被实例化创建。这意味着单例对象不会在应用程序启动时立即创建,而是在需要时才进行延迟初始化。懒汉式的实现相对复杂,需要考虑多线程情况下的并发访问问题,可以通过加锁或双重检查锁定等方式来保证线程安全性。
示例代码(线程安全的懒汉式):
public class Singleton { private static Singleton instance; private Singleton() { // 私有化构造函数,防止外部实例化 } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
饿汉式和懒汉式都是单例模式的典型实现方式,选择哪种实现取决于具体的使用场景和需求。饿汉式适合在对象初始化的成本较低且在整个应用程序生命周期内都需要使用的情况。懒汉式适合在对象初始化成本较高或在应用程序启动时不需要立即初始化的情况。同时,在多线程环境下使用懒汉式时需要注意线程安全性的处理。
工厂方法模式
2023/8/8 10:09:35
2023/8/8 10:09:57
工厂方法模式是一种创建型设计模式,它提供了一种在父类中定义创建对象的接口,而将具体创建对象的工作延迟到子类中进行。这样可以使得一个类的实例化过程由其子类来决定,实现了对象的创建与使用的分离,符合开放封闭原则。
工厂方法模式的主要参与角色如下:
- 抽象工厂(Abstract Factory):定义创建产品对象的接口,声明工厂方法。
- 具体工厂(Concrete Factory):实现抽象工厂接口,负责具体产品的创建。
- 抽象产品(Abstract Product):定义产品对象的接口。
- 具体产品(Concrete Product):实现抽象产品接口,是工厂方法创建的目标对象。
以下是工厂方法模式的简单示例代码:
详情
// 抽象产品接口
public interface Product {
void operation();
}
// 具体产品A
public class ConcreteProductA implements Product {
@Override
public void operation() {
System.out.println("具体产品A的操作");
}
}
// 具体产品B
public class ConcreteProductB implements Product {
@Override
public void operation() {
System.out.println("具体产品B的操作");
}
}
// 抽象工厂接口
public interface Factory {
Product createProduct();
}
// 具体工厂A
public class ConcreteFactoryA implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
// 具体工厂B
public class ConcreteFactoryB implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
在使用工厂方法模式时,客户端代码通过调用具体工厂的工厂方法来创建产品对象,并通过产品接口来使用具体产品。这样一来,客户端就不需要知道具体产品的创建细节,只需要与抽象工厂和抽象产品进行交互,实现了代码的解耦和可扩展性。
工厂方法模式可以灵活地扩展和添加新的产品和工厂,符合开闭原则,同时也降低了运行时的依赖关系,提高了代码的可维护性和可测试性。它常用于需要对产品族进行管理的情况,或者在一个类中无法预知需要创建哪种具体产品的情况下使用。
2023/8/8 10:12:30
2023/8/8 10:12:52
简单工厂模式(Simple Factory Pattern),也称为静态工厂模式,是一种创建型设计模式。它通过一个具体的工厂类,在工厂方法中根据客户端传入的参数来创建并返回不同的产品对象。客户端无需直接实例化产品,只需要通过工厂类来获取所需的产品对象。
简单工厂模式的主要参与角色如下:
- 工厂类(Factory):负责根据客户端传入的参数创建具体产品对象的方法。
- 抽象产品类(Product):定义产品对象的共同接口。
- 具体产品类(Concrete Product):实现抽象产品接口,是工厂类创建的目标对象。
以下是简单工厂模式的示例代码:
详情
// 抽象产品类
public interface Product {
void operation();
}
// 具体产品类A
public class ConcreteProductA implements Product {
@Override
public void operation() {
System.out.println("具体产品A的操作");
}
}
// 具体产品类B
public class ConcreteProductB implements Product {
@Override
public void operation() {
System.out.println("具体产品B的操作");
}
}
// 工厂类
public class Factory {
public static Product createProduct(String type) {
if (type.equals("A")) {
return new ConcreteProductA();
} else if (type.equals("B")) {
return new ConcreteProductB();
}
throw new IllegalArgumentException("Invalid product type.");
}
}
在使用简单工厂模式时,客户端代码调用工厂类的创建方法,并传入指定的参数(产品类型),工厂类根据不同的参数来创建并返回相应的具体产品对象。客户端通过获取到的产品对象,可以直接使用其公共接口进行操作。
简单工厂模式通过将对象的创建逻辑集中在一个工厂类中,降低了客户端与具体产品类的耦合度,使得客户端代码更加简洁和灵活。但同时也存在一定的局限性,当需要新增或修改产品时,需要修改工厂类的代码,违反了开闭原则。因此,简单工厂模式适用于对产品对象的种类较少且不经常变化的情况。
抽象工厂模式
2023/8/8 10:16:18
2023/8/8 10:16:48
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种创建相关或依赖对象族的接口,而无须指定具体的类。它通过定义一个抽象工厂接口,该接口声明了一组用于创建不同产品族的方法,每个方法对应一种产品。
抽象工厂模式的主要参与角色如下:
- 抽象工厂(Abstract Factory):声明创建一组产品的方法。
- 具体工厂(Concrete Factory):实现抽象工厂接口,负责创建一组具体产品。
- 抽象产品(Abstract Product):定义产品的共同接口或抽象类。
- 具体产品(Concrete Product):实现抽象产品接口,是具体工厂创建的目标对象。
以下是抽象工厂模式的示例代码:
详情
// 抽象产品A接口
public interface AbstractProductA {
void operationA();
}
// 具体产品A1
public class ConcreteProductA1 implements AbstractProductA {
@Override
public void operationA() {
System.out.println("具体产品A1的操作");
}
}
// 具体产品A2
public class ConcreteProductA2 implements AbstractProductA {
@Override
public void operationA() {
System.out.println("具体产品A2的操作");
}
}
// 抽象产品B接口
public interface AbstractProductB {
void operationB();
}
// 具体产品B1
public class ConcreteProductB1 implements AbstractProductB {
@Override
public void operationB() {
System.out.println("具体产品B1的操作");
}
}
// 具体产品B2
public class ConcreteProductB2 implements AbstractProductB {
@Override
public void operationB() {
System.out.println("具体产品B2的操作");
}
}
// 抽象工厂接口
public interface AbstractFactory {
AbstractProductA createProductA();
AbstractProductB createProductB();
}
// 具体工厂1
public class ConcreteFactory1 implements AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB1();
}
}
// 具体工厂2
public class ConcreteFactory2 implements AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB2();
}
}
在使用抽象工厂模式时,客户端通过具体工厂类来创建一组相关的产品对象,并通过产品接口来使用这些产品。客户端无需关心具体的产品对象是如何创建的,只需要与抽象工厂和抽象产品进行交互。
抽象工厂模式能够保证一组相关的产品对象被一起创建,确保了产品之间的兼容性。同时,它也符合开闭原则,当需要新增一组产品时,只需要扩展抽象工厂和具体工厂即可,而不需要修改客户端代码。抽象工厂模式适用于需要创建一系列相互关联或依赖的产品族的场景。
建造者模式
2023/8/8 10:20:10
2023/8/8 10:20:36
建造者模式(Builder Pattern)是一种创建型设计模式,它将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式的主要参与角色如下:
- 产品类(Product):定义复杂对象的组成和操作。
- 抽象建造者类(Builder):定义构建产品各个部分的抽象方法,并声明一个用于获取构建结果的方法。
- 具体建造者类(Concrete Builder):实现抽象建造者类的方法,具体控制产品的构建过程,以及返回最终构建结果。
- 指挥者类(Director):调用具体建造者类中的方法,按照特定的顺序来构建产品。
以下是建造者模式的示例代码:
详情
// 产品类
public class Product {
private String partA;
private String partB;
private String partC;
public void setPartA(String partA) {
this.partA = partA;
}
public void setPartB(String partB) {
this.partB = partB;
}
public void setPartC(String partC) {
this.partC = partC;
}
public void operation() {
System.out.println("产品操作,包括:" + partA + "、" + partB + "、" + partC);
}
}
// 抽象建造者类
public abstract class Builder {
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
public abstract Product getResult();
}
// 具体建造者类
public class ConcreteBuilder extends Builder {
private Product product;
public ConcreteBuilder() {
this.product = new Product();
}
@Override
public void buildPartA() {
product.setPartA("PartA");
}
@Override
public void buildPartB() {
product.setPartB("PartB");
}
@Override
public void buildPartC() {
product.setPartC("PartC");
}
@Override
public Product getResult() {
return product;
}
}
// 指挥者类
public class Director {
public void construct(Builder builder) {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
}
}
在使用建造者模式时,客户端通过指挥者类来创建产品对象,指挥者类调用具体建造者类的方法来构建产品的各个部分。客户端只需实例化指挥者类和具体建造者类,并将具体建造者类传递给指挥者类的构造函数或设置方法,在调用指挥者类的构建方法后,即可获取到最终构建好的产品对象。
建造者模式将产品的组装过程与客户端代码分离,使得产品的构建过程可独立变化,且易于扩展。同时,它也符合单一职责原则,每个具体建造者只负责构建一个特定的产品。建造者模式适用于构建过程复杂且需要对构建过程进行精细控制的情况。
原型模式
2023/8/8 10:22:57
2023/8/8 10:23:38
原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制现有对象来创建新对象,而不是通过直接实例化。原型模式通过使用原型实例作为创建对象的基础,然后通过复制这个原型来创建新的对象。
原型模式的主要参与角色如下:
- 原型接口(Prototype):声明克隆自身的方法。
- 具体原型类(Concrete Prototype):实现克隆方法,即实现对象的复制。
- 客户端(Client):通过调用原型的克隆方法复制对象。
以下是原型模式的示例代码:
详情
// 原型接口
public interface Prototype {
Prototype clone();
}
// 具体原型类
public class ConcretePrototype implements Prototype {
private String data;
public ConcretePrototype(String data) {
this.data = data;
}
// 实现克隆方法
@Override
public Prototype clone() {
return new ConcretePrototype(data);
}
public void setData(String data) {
this.data = data;
}
public String getData() {
return data;
}
}
// 客户端
public class Client {
public static void main(String[] args) {
ConcretePrototype prototype = new ConcretePrototype("原型对象");
ConcretePrototype clone = (ConcretePrototype) prototype.clone();
System.out.println("原型对象数据:" + prototype.getData());
System.out.println("克隆对象数据:" + clone.getData());
}
}
在使用原型模式时,客户端通过调用原型对象的克隆方法来创建新的对象。通过复制原型对象,即可获得一个新的对象,而无需关心具体的创建过程。
原型模式适用于以下情况:
- 当创建对象的过程比较复杂或耗时时,可以使用原型模式来简化对象的创建过程。
- 当需要创建大量相似的对象时,可以使用原型模式来减少重复创建的成本。
- 当希望对已有对象进行修改时,可以首先克隆一个对象,然后在其基础上进行修改,以避免影响原始对象。
需要注意的是,在使用原型模式时,克隆方法可以是浅克隆(只复制对象的基本数据类型属性)或深克隆(同时复制对象的引用类型属性)。根据具体的需求,选择适合的克隆方式。
适配器模式
2023/8/8 10:26:29
2023/8/8 10:26:52
适配器模式(Adapter Pattern)是一种结构型设计模式,它用于将一个类的接口转换成客户端所期望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的类能够协同工作。
适配器模式的主要参与角色如下:
- 目标接口(Target):定义客户端使用的接口。
- 适配器类(Adapter):实现目标接口,并持有需要被适配的对象的引用。
- 需要适配的类(Adaptee):需要被适配的类,它包含了一些已经存在的、但接口不兼容的方法。
- 客户端(Client):通过目标接口调用适配器的方法来使用被适配者的功能。
以下是适配器模式的示例代码:
详情
// 目标接口
public interface Target {
void request();
}
// 适配器类
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
// 需要适配的类
public class Adaptee {
public void specificRequest() {
System.out.println("被适配者的方法");
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target adapter = new Adapter(adaptee);
adapter.request();
}
}
在适配器模式中,客户端通过目标接口调用适配器的方法来使用被适配者的功能。适配器类内部持有了需要适配的类的引用,在实现目标接口的方法时,适配器类会调用被适配者的相应方法来完成功能的适配。
适配器模式主要用于以下情况:
- 当系统中有现有的类,其接口与客户端所期望的接口不兼容时,可以使用适配器模式进行接口的转换。
- 当需要复用一些现有的类,但是这些类的接口与其他类的接口不兼容时,可以使用适配器模式进行接口的适配。
适配器模式将不兼容的接口进行适配,使得原本不能在一起工作的类能够协同工作,提高了代码的复用性和灵活性。同时,它也符合开闭原则,可以在不修改现有代码的情况下引入新的适配器类。
桥接模式
2023/8/8 10:28:13
2023/8/8 10:28:40
桥接模式(Bridge Pattern)是一种结构型设计模式,它将抽象部分与实现部分分离,使得它们可以独立地变化。桥接模式通过将功能层次结构的一个维度与其实现层次结构的一个维度进行组合,可以在程序中灵活地应对变化。
桥接模式的主要参与角色如下:
- 抽象类(Abstraction):定义抽象部分的接口,同时对实现部分的引用。
- 扩展抽象类(Refined Abstraction):扩展抽象类,可以通过扩展抽象类中的方法来添加额外的功能。
- 实现类接口(Implementor):定义实现部分的接口,提供基本操作的方法。
- 具体实现类(Concrete Implementor):实现实现类接口,提供具体操作的方法。
以下是桥接模式的示例代码:
详情
// 抽象类
public abstract class Abstraction {
protected Implementor implementor;
public Abstraction(Implementor implementor) {
this.implementor = implementor;
}
public abstract void operation();
}
// 扩展抽象类
public class RefinedAbstraction extends Abstraction {
public RefinedAbstraction(Implementor implementor) {
super(implementor);
}
@Override
public void operation() {
// 扩展抽象类中的方法
System.out.println("扩展抽象类的操作");
implementor.operationImpl();
}
}
// 实现类接口
public interface Implementor {
void operationImpl();
}
// 具体实现类
public class ConcreteImplementorA implements Implementor {
@Override
public void operationImpl() {
System.out.println("具体实现类 A 的操作");
}
}
public class ConcreteImplementorB implements Implementor {
@Override
public void operationImpl() {
System.out.println("具体实现类 B 的操作");
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Implementor implementorA = new ConcreteImplementorA();
Abstraction abstractionA = new RefinedAbstraction(implementorA);
abstractionA.operation();
Implementor implementorB = new ConcreteImplementorB();
Abstraction abstractionB = new RefinedAbstraction(implementorB);
abstractionB.operation();
}
}
在桥接模式中,抽象部分和实现部分通过组合的方式进行关联。抽象部分聚合了实现部分的对象,并调用实现部分的方法来完成具体的操作。通过将抽象部分与实现部分分离,可以使它们可以独立地变化,从而提高系统的灵活性和可扩展性。
桥接模式适用于以下情况:
- 当一个系统需要在抽象部分和实现部分之间有多个维度的变化时,可以使用桥接模式来解耦这些维度的变化。
- 当需要让抽象部分和实现部分可以独立地进行扩展和变化时,可以使用桥接模式。
需要注意的是,在使用桥接模式时,抽象部分和实现部分可以分别进行扩展和变化,从而实现更灵活的系统设计。
组合模式
2023/8/8 10:30:12
2023/8/8 10:30:41
组合模式(Composite Pattern)是一种结构型设计模式,它允许将对象组织成树状结构,并且能够以统一的方式处理单个对象和组合对象。
组合模式的主要参与角色如下:
- 组件抽象类(Component):定义组合中所有对象的共同接口,包括管理子组件的方法。
- 叶子节点(Leaf):表示组合中的叶子对象。叶子节点没有子节点。
- 容器节点(Composite):表示组合中的容器对象。容器节点可以拥有子节点。
以下是组合模式的示例代码:
详情
// 组件抽象类
public abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
public abstract void operation();
public abstract void add(Component component);
public abstract void remove(Component component);
public abstract void getChild(int index);
}
// 叶子节点
public class Leaf extends Component {
public Leaf(String name) {
super(name);
}
@Override
public void operation() {
System.out.println("叶子节点 " + name + " 的操作");
}
@Override
public void add(Component component) {
System.out.println("叶子节点不能添加子节点");
}
@Override
public void remove(Component component) {
System.out.println("叶子节点没有子节点,无法删除");
}
@Override
public void getChild(int index) {
System.out.println("叶子节点没有子节点");
}
}
// 容器节点
public class Composite extends Component {
private List<Component> components = new ArrayList<>();
public Composite(String name) {
super(name);
}
@Override
public void operation() {
System.out.println("容器节点 " + name + " 的操作");
for (Component component : components) {
component.operation();
}
}
@Override
public void add(Component component) {
components.add(component);
}
@Override
public void remove(Component component) {
components.remove(component);
}
@Override
public void getChild(int index) {
System.out.println("子节点 " + components.get(index).name);
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Component leaf1 = new Leaf("Leaf 1");
Component leaf2 = new Leaf("Leaf 2");
Component composite1 = new Composite("Composite 1");
Component composite2 = new Composite("Composite 2");
composite1.add(leaf1);
composite1.add(leaf2);
composite1.add(composite2);
composite1.operation();
composite1.getChild(0);
}
}
在组合模式中,组件抽象类定义了组合中的对象的共同接口,包括管理子组件的方法。叶子节点表示组合中的叶子对象,它没有子节点。容器节点表示组合中的容器对象,它可以拥有子节点。通过组合的方式,在容器节点中可以灵活地组织和处理多个对象。
组合模式适用于以下情况:
- 当需要将对象组织成树状结构,并且以统一的方式处理单个对象和组合对象时,可以使用组合模式。
- 当希望客户端可以一致地对待简单对象和复杂对象时,可以使用组合模式。
组合模式能够提供一种统一的方式来处理单个对象和组合对象,从而简化了系统的设计和代码的实现。它使得客户端可以将复杂的层次结构看作是一个统一的对象,提高了系统的灵活性和可扩展性。
装饰器模式
2023/8/8 10:32:06
2023/8/8 10:32:35
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许在不改变已有对象的基础上,动态地为对象添加额外的功能。
装饰器模式的主要参与角色如下:
- 抽象组件(Component):定义了被装饰对象和装饰器对象的共同接口。
- 具体组件(ConcreteComponent):实现了抽象组件接口,并定义了被装饰对象。
- 抽象装饰器(Decorator):继承了抽象组件接口,并持有一个抽象组件对象的引用。
- 具体装饰器(ConcreteDecorator):继承了抽象装饰器接口,负责给被装饰对象添加额外的功能。
以下是装饰器模式的示例代码:
详情
// 抽象组件
public interface Component {
void operation();
}
// 具体组件
public class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("执行具体操作");
}
}
// 抽象装饰器
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation();
}
}
// 具体装饰器A
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
addedBehavior();
}
private void addedBehavior() {
System.out.println("添加额外的行为A");
}
}
// 具体装饰器B
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
addedBehavior();
}
private void addedBehavior() {
System.out.println("添加额外的行为B");
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Component component = new ConcreteComponent();
Component decoratorA = new ConcreteDecoratorA(component);
Component decoratorB = new ConcreteDecoratorB(decoratorA);
decoratorB.operation();
}
}
在装饰器模式中,抽象组件定义了被装饰对象和装饰器对象的共同接口。具体组件实现了抽象组件接口,并定义了被装饰对象。抽象装饰器继承了抽象组件接口,并持有一个抽象组件对象的引用。具体装饰器继承了抽象装饰器接口,负责给被装饰对象添加额外的功能。
装饰器模式通过递归组合的方式,能够动态地为对象添加新行为,而不需要修改原有的代码。它遵循开闭原则,使得系统更加灵活、可扩展和维护。
装饰器模式适用于以下情况:
- 当需要动态地为对象添加功能,而又不希望使用继承或修改原有类时,可以使用装饰器模式。
- 当要求对多个对象进行灵活组合,以实现多种不同的功能时,可以使用装饰器模式。
装饰器模式提供了一种灵活的方式来扩展对象的功能,同时避免了使用继承带来的静态特性。它使得功能的添加和组合变得简单,且具备良好的扩展性和可维护性。
外观模式
2023/8/8 10:34:13
2023/8/8 10:34:35
外观模式(Facade Pattern)是一种结构型设计模式,它提供了一个统一的接口,用于访问子系统中的一组接口。外观模式定义了一个高层接口,使得子系统更加容易使用。
外观模式的主要参与角色如下:
- 外观(Facade):提供了一个简单的接口,用于访问子系统的功能。
- 子系统(Subsystems):实现了具体的功能,处理外观接口指派的任务。
以下是外观模式的示例代码:
详情
// 子系统A
public class SubsystemA {
public void operationA() {
System.out.println("子系统A的操作");
}
}
// 子系统B
public class SubsystemB {
public void operationB() {
System.out.println("子系统B的操作");
}
}
// 外观
public class Facade {
private SubsystemA subsystemA;
private SubsystemB subsystemB;
public Facade() {
this.subsystemA = new SubsystemA();
this.subsystemB = new SubsystemB();
}
public void operation() {
subsystemA.operationA();
subsystemB.operationB();
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Facade facade = new Facade();
facade.operation();
}
}
在外观模式中,外观提供了一个简单的接口,封装了一系列子系统的复杂操作。子系统实现了具体的功能,处理外观接口指派的任务。
使用外观模式的好处是在客户端和子系统之间建立了一个简化的接口,降低了客户端与子系统之间的耦合度。客户端只需要与外观进行交互,无需直接调用子系统的功能。外观模式提供了一种简单、统一的方式来使用复杂子系统,并隐藏了子系统的实现细节。
外观模式适用于以下情况:
- 当需要简化多个子系统的接口并提供一个统一的接口时,可以使用外观模式。
- 当需要将客户端从子系统的实现细节中解耦时,可以使用外观模式。
- 当需要对子系统进行重构或修改,但不希望影响到客户端代码时,可以使用外观模式。
外观模式能够提供一个简化的接口来访问复杂的子系统,减少了客户端与子系统之间的耦合度,提高了系统的灵活性和可扩展性。它可以使得代码更加易于理解和维护,并支持系统的分层设计和封装。
享元模式
2023/8/8 10:36:08
2023/8/8 10:36:39
享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享对象来有效地支持大量细粒度的对象。享元模式旨在减少对象的内存占用和提高性能。
享元模式的核心思想是将对象的状态分为内部状态(Intrinsic State)和外部状态(Extrinsic State)。内部状态是可以共享的,存储在享元对象内部;外部状态是不可共享的,由客户端在使用时传入。
享元模式的主要参与角色如下:
- 享元工厂(Flyweight Factory):负责创建和管理享元对象,提供一个池来存储已创建的享元对象。
- 抽象享元(Flyweight):定义了享元对象的接口,声明了需要接收外部状态的方法。
- 具体享元(Concrete Flyweight):实现了抽象享元接口,并存储了内部状态。
- 客户端(Client):使用享元对象的客户端,在使用时传入外部状态。
以下是享元模式的示例代码:
详情
// 抽象享元
public interface Flyweight {
void operation(String externalState);
}
// 具体享元
public class ConcreteFlyweight implements Flyweight {
private String intrinsicState;
public ConcreteFlyweight(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
@Override
public void operation(String externalState) {
System.out.println("具体享元对象:" + intrinsicState + ",外部状态:" + externalState);
}
}
// 享元工厂
public class FlyweightFactory {
private Map<String, Flyweight> flyweightMap = new HashMap<>();
public Flyweight getFlyweight(String key) {
if (flyweightMap.containsKey(key)) {
return flyweightMap.get(key);
} else {
Flyweight flyweight = new ConcreteFlyweight(key);
flyweightMap.put(key, flyweight);
return flyweight;
}
}
}
// 客户端
public class Client {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
// 获取享元对象并使用不同的外部状态
Flyweight flyweight1 = factory.getFlyweight("A");
flyweight1.operation("外部状态1");
Flyweight flyweight2 = factory.getFlyweight("A");
flyweight2.operation("外部状态2");
Flyweight flyweight3 = factory.getFlyweight("B");
flyweight3.operation("外部状态3");
}
}
在享元模式中,享元工厂负责创建和管理享元对象,并提供一个池来存储已创建的享元对象。抽象享元定义了享元对象的接口,声明了需要接收外部状态的方法。具体享元实现了抽象享元接口,并存储了内部状态。
通过共享对象的内部状态,享元模式可以减少对象的数量,从而节省内存空间。当多个对象具有相同的内部状态时,可以共享一个享元对象,而不需要为每个对象都创建一个新的对象。
享元模式适用于以下情况:
- 当系统中存在大量的相似对象,并且这些对象的区别仅在于某些外部状态时,可以使用享元模式。
- 当需要创建大量的对象,但又不希望占用过多的内存空间时,可以使用享元模式。
享元模式可以有效地减少对象的数量,降低系统的内存占用和提高性能。它提供了一种优化方案来处理大量细粒度的对象,并支持对象的共享和复用。然而,享元模式也增加了系统的复杂性,需要注意对内部状态和外部状态的处理。
代理模式
2023/8/8 10:38:02
2023/8/8 10:38:28
代理模式是一种结构型设计模式,它通过引入一个代理对象来控制对其他对象的访问。代理模式提供了一种间接访问目标对象的方式,可以在不改变目标对象的情况下,增加额外的功能或控制访问。
代理模式的主要参与角色如下:
- 抽象主题(Subject):定义了目标对象和代理对象的共同接口,可以是接口或抽象类。
- 真实主题(Real Subject):实现了抽象主题接口,是真正需要访问的对象。
- 代理(Proxy):实现了抽象主题接口,并持有一个真实主题的引用,它可以在调用真实主题之前或之后执行额外的操作。
以下是代理模式的示例代码:
详情
// 抽象主题
public interface Subject {
void request();
}
// 真实主题
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("真实主题处理请求");
}
}
// 代理
public class Proxy implements Subject {
private RealSubject realSubject;
public Proxy(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
// 在调用真实主题之前或之后执行额外的操作
System.out.println("代理处理请求");
realSubject.request();
}
}
// 客户端
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Proxy proxy = new Proxy(realSubject);
// 通过代理访问真实主题
proxy.request();
}
}
在代理模式中,客户端通过代理对象来访问真实对象。代理对象在调用真实对象之前或之后可以执行额外的操作。这种间接的访问方式可以在不直接访问真实对象的情况下,对访问进行控制或增加额外的功能。
代理模式可以实现以下功能:
- 远程代理(Remote Proxy):控制对远程对象的访问,使得客户端可以透明地访问远程对象。
- 虚拟代理(Virtual Proxy):延迟创建对象的代理,直到客户端真正需要使用它时才创建。
- 安全代理(Protection Proxy):控制对对象的访问权限,根据用户的身份和权限判断是否允许访问。
- 缓存代理(Caching Proxy):为耗时的操作提供缓存,避免重复执行相同的操作。
代理模式可以提供一种灵活的替代方案,可以在不改变现有代码的情况下,增加新的功能或控制访问。然而,代理模式会引入额外的代理对象,增加了系统的复杂性和开销。在使用代理模式时,需要权衡好额外功能和性能的考虑。
模板方法模式
2023/8/8 10:39:58
2023/8/8 10:40:26
模板方法模式是一种行为型设计模式,它定义了算法的骨架,并允许子类重写某些步骤。模板方法模式通过将共同的算法步骤放在父类中,而将特定的实现延迟到子类中,以达到代码复用和扩展的目的。
模板方法模式的核心思想是,定义一个抽象类并声明一个模板方法,在模板方法中按照固定的算法顺序调用其他的抽象方法。子类继承这个抽象类并实现其中的具体步骤,以完成整个算法的执行。
模板方法模式的主要参与角色如下:
- 抽象类(Abstract Class):定义算法的骨架,包含一个模板方法和多个抽象方法,可以有默认实现或空实现。
- 具体类(Concrete Class):继承抽象类,实现其中的抽象方法,完成算法的具体步骤。
以下是模板方法模式的示例代码:
详情
// 抽象类
public abstract class AbstractClass {
public void templateMethod() {
// 步骤1
step1();
// 步骤2
step2();
// 步骤3
step3();
}
protected abstract void step1();
protected abstract void step2();
protected abstract void step3();
}
// 具体类
public class ConcreteClass extends AbstractClass {
@Override
protected void step1() {
System.out.println("执行步骤1");
}
@Override
protected void step2() {
System.out.println("执行步骤2");
}
@Override
protected void step3() {
System.out.println("执行步骤3");
}
}
// 客户端
public class Client {
public static void main(String[] args) {
AbstractClass abstractClass = new ConcreteClass();
abstractClass.templateMethod();
}
}
在模板方法模式中,抽象类定义了算法的骨架,其中的模板方法包含了一系列的步骤调用。这些步骤可以是抽象方法,由子类实现具体逻辑;也可以是具体方法,有默认的实现或空实现。
通过将具体步骤的实现推迟到子类中,模板方法模式允许在不改变算法结构的情况下,可以对算法的特定步骤进行灵活的扩展和自定义。子类可以通过重写父类中的抽象方法,来实现自己的特定逻辑和行为,从而完成整个算法的执行。
模板方法模式常用于以下情况:
- 当多个实现类有共同的算法骨架,但各自的具体步骤可能有所不同时,可以使用模板方法模式。
- 当需要控制算法的执行流程,并且希望在不改变算法结构的情况下进行扩展和自定义时,可以使用模板方法模式。
模板方法模式可以提高代码复用性、扩展性和可维护性,但也带来了类的增加和继承关系的固定的问题。在使用模板方法模式时,需要权衡好抽象类和具体子类的关系,并合理划分不同步骤的职责。
命令模式
2023/8/8 10:41:51
2023/8/8 10:42:22
命令模式是一种行为型设计模式,它通过将请求封装成对象,从而使得可以用不同的请求对客户端进行参数化。这样客户端可以使用不同的请求来参数化对象,并且具体的请求者与接收者解耦。
命令模式的核心思想是将请求封装成一个对象,包括请求的操作、参数和接收者等信息,然后通过调用该对象的方法来执行请求。这样可以将请求的发送者和请求的接收者解耦,让发送者只关注发送请求的对象,而不需要知道具体的接收者是谁,同时也方便了请求的撤销和重做等操作。
命令模式的主要参与角色如下:
- 命令接口(Command):定义执行命令的统一接口,通常包含一个执行方法。
- 具体命令类(Concrete Command):实现命令接口,负责执行具体的命令操作。
- 请求者类(Invoker):调用命令对象来执行请求,可以持有命令对象或通过命令工厂来获取命令对象。
- 接收者类(Receiver):执行具体操作的对象,真正处理命令的逻辑。
以下是命令模式的示例代码:
详情
// 命令接口
public interface Command {
void execute();
}
// 具体命令类
public class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.action();
}
}
// 请求者类
public class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
}
// 接收者类
public class Receiver {
public void action() {
System.out.println("执行具体操作");
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.executeCommand();
}
}
在命令模式中,客户端创建一个具体的命令对象,并且将该命令对象传递给请求者类。请求者类持有该命令对象,并在需要执行命令的时候调用命令对象的执行方法。命令对象内部实际上是调用具体的接收者类来执行具体的操作。
通过将命令请求封装成对象,命令模式实现了请求者和接收者之间的解耦,增加了系统的灵活性和可扩展性。客户端可以根据需要动态地添加、替换和删除命令对象,而无需修改原有的代码。此外,命令模式还支持请求的撤销和重做等操作,通过保存命令的历史记录,可以实现对命令的撤销和重做。
命令模式适用于以下情况:
- 当需要将请求调用者和具体的接收者解耦时,可以使用命令模式。
- 当需要在不同的时间指定、排队和执行请求时,可以使用命令模式。
- 当需要支持请求的撤销和重做等操作时,可以使用命令模式。
命令模式能够降低系统的耦合度,提供了一种更为灵活的方式来设计和组织代码。但同时也会增加代码的复杂性,因为需要引入额外的命令类和接口。在使用命令模式时,需要权衡好灵活性和复杂性之间的平衡,合理划分命令的粒度,确保命令的扩展和维护的可行性。
迭代器模式
2023/8/8 10:43:46
2023/8/8 10:44:21
迭代器模式(Iterator Pattern)是一种行为型设计模式,它提供了一种方法来顺序访问一个容器对象中的各个元素,而又不暴露该容器的内部表示。通过使用迭代器,可以在不关心容器内部结构的情况下,对容器中的元素进行遍历和操作。
迭代器模式的核心思想是将对容器的遍历操作从容器中分离出来,放到一个独立的迭代器类中。迭代器类封装了遍历容器的细节,包含了对容器的引用以及当前遍历位置等信息。客户端通过迭代器的接口来访问元素,而不需要知道容器的具体实现细节。
迭代器模式的参与角色如下:
- 迭代器接口(Iterator):定义了遍历元素的通用接口,包括获取下一个元素、判断是否还有元素等方法。
- 具体迭代器类(Concrete Iterator):实现迭代器接口,负责实现具体的遍历逻辑。
- 容器接口(Container):定义了获取迭代器的方法。
- 具体容器类(Concrete Container):实现容器接口,负责创建具体的迭代器对象。
- 客户端(Client):使用迭代器来遍历容器中的元素。
以下是迭代器模式的示例代码:
详情
// 迭代器接口
public interface Iterator<T> {
boolean hasNext();
T next();
}
// 具体迭代器类
public class ConcreteIterator<T> implements Iterator<T> {
private List<T> elements;
private int position;
public ConcreteIterator(List<T> elements) {
this.elements = elements;
this.position = 0;
}
@Override
public boolean hasNext() {
return position < elements.size();
}
@Override
public T next() {
T element = elements.get(position);
position++;
return element;
}
}
// 容器接口
public interface Container<T> {
Iterator<T> createIterator();
}
// 具体容器类
public class ConcreteContainer<T> implements Container<T> {
private List<T> elements;
public ConcreteContainer(List<T> elements) {
this.elements = elements;
}
@Override
public Iterator<T> createIterator() {
return new ConcreteIterator<>(elements);
}
}
// 客户端
public class Client {
public static void main(String[] args) {
List<String> elements = new ArrayList<>();
elements.add("元素1");
elements.add("元素2");
elements.add("元素3");
Container<String> container = new ConcreteContainer<>(elements);
Iterator<String> iterator = container.createIterator();
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println(element);
}
}
}
在迭代器模式中,容器对象负责提供创建迭代器的接口,而具体的迭代器对象负责实现遍历容器元素的逻辑。客户端通过容器的接口获取迭代器对象,然后使用迭代器对象来遍历容器中的元素。
迭代器模式提供了一种统一的方式来遍历不同类型的容器,使得容器的内部结构对客户端透明,同时也增加了容器的灵活性和扩展性。如果需要遍历不同类型的容器,只需提供对应的迭代器实现即可,而无需修改已有的代码。
迭代器模式适用于以下情况:
- 当需要遍历一个容器对象的元素,而又不希望暴露容器的内部结构时,可以使用迭代器模式。
- 当需要对容器的遍历操作进行封装,以便于复用和扩展时,可以使用迭代器模式。
- 当需要为不同类型的容器提供一个统一的遍历接口时,可以使用迭代器模式。
迭代器模式能够解耦遍历算法和容器结构,使得客户端能够独立地操作容器对象和迭代器对象。但需要注意的是,迭代器模式会增加代码的复杂性,因为需要引入迭代器接口和具体迭代器类。在使用迭代器模式时,需要权衡好灵活性和复杂性之间的平衡,确保迭代器的设计和实现合理有效。
观察者模式
2023/8/8 10:45:40
2023/8/8 10:46:17
观察者模式(Observer Pattern)是一种行为型设计模式,它在对象之间定义了一种一对多的依赖关系,使得当一个对象状态发生变化时,其相关依赖对象都能够自动更新。
观察者模式的核心思想是将对象之间的关系从静态的编译时绑定转换为动态的运行时绑定。在观察者模式中,存在两种角色:观察者和被观察者。被观察者节点维护一个观察者列表,当其状态发生变化时,会遍历观察者列表,并通知所有的观察者对象执行相应的更新操作。
观察者模式的参与角色如下:
- 抽象主题(Subject):定义了被观察者的接口,提供了观察者注册、注销以及通知观察者的方法。
- 具体主题(Concrete Subject):实现了抽象主题,维护了观察者列表,并在状态发生变化时通知观察者。
- 抽象观察者(Observer):定义了观察者的接口,包括接收通知和更新状态等方法。
- 具体观察者(Concrete Observer):实现了抽象观察者接口,在接收到通知后更新自身的状态。
以下是观察者模式的示例代码:
详情
// 抽象主题
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体主题
public class ConcreteSubject implements Subject {
private List<Observer> observers;
private int state;
public ConcreteSubject() {
this.observers = new ArrayList<>();
this.state = 0;
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(state);
}
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
}
// 抽象观察者
public interface Observer {
void update(int state);
}
// 具体观察者
public class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(int state) {
System.out.println(name + " 收到通知,状态更新为:" + state);
}
}
// 客户端
public class Client {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
Observer observer1 = new ConcreteObserver("观察者1");
Observer observer2 = new ConcreteObserver("观察者2");
subject.registerObserver(observer1);
subject.registerObserver(observer2);
subject.setState(1);
subject.removeObserver(observer1);
subject.setState(2);
}
}
在观察者模式中,被观察者维护了一个观察者列表,并提供了注册、注销以及通知观察者的方法。具体的观察者实现了观察者接口,在接收到被观察者的通知时更新自身的状态。
观察者模式可以实现对象之间的松耦合,以及动态的依赖关系。被观察者和观察者之间是一种单向的依赖关系,被观察者不知道观察者的具体实现,只负责通知观察者。这样,在系统扩展时,可以方便地增加新的观察者,而无需修改被观察者的代码。
观察者模式适用于以下场景:
- 当一个对象的改变需要同时通知其他对象,并且不希望与被通知的对象形成紧耦合关系时,可以使用观察者模式。
- 当一个对象的改变需要引起其他多个对象的更新操作时,可以使用观察者模式。
- 当存在一对多的关系,一个对象的改变需要通知一组对象时,可以使用观察者模式。
需要注意的是,观察者模式可能会导致系统中观察者链过长,影响性能。因此,在使用观察者模式时,需要注意控制观察者的数量和更新频率,避免出现性能问题。另外,在使用观察者模式时,也要考虑线程安全等并发访问的问题。
中介者模式
2023/8/8 10:47:52
2023/8/8 10:48:28
中介者模式(Mediator Pattern)是一种行为型设计模式,它通过将对象之间的交互行为封装到一个中介者对象中,从而使对象之间不直接进行通信,而是通过中介者进行沟通和协作。
中介者模式的核心思想是解耦对象之间的直接交互,减少对象之间的依赖关系,使得系统更易于维护和扩展。在中介者模式中,存在两种角色:中介者和同事类。中介者负责协调和控制同事类之间的交互,同事类则通过中介者来进行通信。
中介者模式的参与角色如下:
- 抽象中介者(Mediator):定义了同事类之间交互的接口,提供了注册和发送消息的方法。
- 具体中介者(Concrete Mediator):实现了抽象中介者接口,协调和控制各个同事类之间的交互。
- 抽象同事类(Colleague):定义了同事类的接口,包括向中介者注册、接收消息和发送消息等方法。
- 具体同事类(Concrete Colleague):实现了抽象同事类接口,在需要和其他同事类进行通信时,通过中介者来发送和接收消息。
以下是中介者模式的示例代码:
详情
// 抽象中介者
public interface Mediator {
void register(Colleague colleague);
void send(String message, Colleague sender);
}
// 具体中介者
public class ConcreteMediator implements Mediator {
private List<Colleague> colleagues;
public ConcreteMediator() {
this.colleagues = new ArrayList<>();
}
@Override
public void register(Colleague colleague) {
colleagues.add(colleague);
}
@Override
public void send(String message, Colleague sender) {
for (Colleague colleague : colleagues) {
if (colleague != sender) {
colleague.receive(message);
}
}
}
}
// 抽象同事类
public abstract class Colleague {
protected Mediator mediator;
protected String name;
public Colleague(Mediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public abstract void send(String message);
public abstract void receive(String message);
}
// 具体同事类
public class ConcreteColleague extends Colleague {
public ConcreteColleague(Mediator mediator, String name) {
super(mediator, name);
}
@Override
public void send(String message) {
mediator.send(message, this);
}
@Override
public void receive(String message) {
System.out.println(name + " 收到消息:" + message);
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Mediator mediator = new ConcreteMediator();
Colleague colleague1 = new ConcreteColleague(mediator, "同事1");
Colleague colleague2 = new ConcreteColleague(mediator, "同事2");
Colleague colleague3 = new ConcreteColleague(mediator, "同事3");
mediator.register(colleague1);
mediator.register(colleague2);
mediator.register(colleague3);
colleague1.send("大家好!");
colleague2.send("你好!");
}
}
在中介者模式中,中介者负责协调和控制同事类之间的交互。每个同事类都持有一个对中介者对象的引用,通过中介者来进行通信。当一个同事类需要发送消息时,它会调用中介者的发送方法,并将自身作为参数传递给中介者。中介者接收到消息后,会遍历所有的同事类,并将消息发送给其他同事类(除了发送者)。
中介者模式可以实现对象之间的松耦合,减少了对象之间的直接依赖关系。通过引入中介者对象,将交互行为集中管理,使得系统更易于理解、扩展和维护。中介者模式特别适用于对象之间的交互复杂、耦合度高的场景。
需要注意的是,中介者模式可能会导致中介者对象的逻辑复杂化,成为系统的瓶颈。因此,在使用中介者模式时,需要权衡各种因素,确保能够达到设计的目标,并且避免过度集中化的问题。另外,中介者模式也需要考虑线程安全等并发访问的问题。
备忘录模式
2023/8/8 10:49:54
2023/8/8 10:50:29
备忘录模式(Memento Pattern)是一种行为型设计模式,它允许在不破坏封装性的前提下捕获一个对象的内部状态,并在该对象之外保存这个状态。这样,该对象可以随时恢复到之前的状态。
备忘录模式的核心思想是将要保存的对象的状态封装到备忘录对象中,并将备忘录对象存储在备忘录管理者中。备忘录管理者负责保存和管理备忘录对象,有需要的时候可以将备忘录对象还原给原始对象。
备忘录模式的参与角色如下:
- 原始对象(Originator):负责创建备忘录对象,并可以使用备忘录对象来恢复自身状态。
- 备忘录对象(Memento):用于存储原始对象的状态。
- 备忘录管理者(Caretaker):负责保存和管理备忘录对象。
以下是备忘录模式的示例代码:
详情
// 备忘录对象
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// 原始对象
public class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
public Memento createMemento() {
return new Memento(state);
}
public void restoreMemento(Memento memento) {
this.state = memento.getState();
}
}
// 备忘录管理者
public class Caretaker {
private Memento memento;
public void saveMemento(Memento memento) {
this.memento = memento;
}
public Memento retrieveMemento() {
return memento;
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("State 1");
System.out.println("初始状态:" + originator.getState());
// 保存备忘录
caretaker.saveMemento(originator.createMemento());
originator.setState("State 2");
System.out.println("更新状态:" + originator.getState());
// 恢复到之前的状态
originator.restoreMemento(caretaker.retrieveMemento());
System.out.println("恢复状态:" + originator.getState());
}
}
在备忘录模式中,原始对象负责创建备忘录对象,并可以使用备忘录对象来恢复自身状态。备忘录对象用于存储原始对象的状态,并提供了获取状态的方法。备忘录管理者负责保存和管理备忘录对象,可以将备忘录对象保存起来或取出来,以便在需要的时候将状态还原给原始对象。
备忘录模式可以实现对象状态的保存和恢复,同时又遵循了封装原则,不会破坏对象的封装性。它可以在不暴露对象内部结构的情况下,保存和恢复对象的状态。备忘录模式特别适用于需要保存和还原对象状态的场景,例如撤销操作、游戏存档等。
需要注意的是,备忘录模式可能会消耗较多的内存,特别是当原始对象的状态比较大或者备忘录管理者需要管理多个备忘录对象时。因此,在使用备忘录模式时,需要权衡存储和性能的问题,并确保备忘录管理者的职责清晰。另外,备忘录模式也需要考虑对象状态的一致性和隐私性等问题。
解释器模式
2023/8/8 10:52:06
2023/8/8 10:52:34
解释器模式(Interpreter Pattern)是一种行为型设计模式,用于定义一个语言的文法,并提供解释器来解释执行这个语言中的句子。
解释器模式的核心思想是将一个语言的文法表示为一个类的层次结构,并使用解释器对象来表示语言中的各种句子。每个句子都可以被解释器对象解释执行,从而实现对整个语言的解析和执行。
解释器模式的参与角色如下:
- 抽象表达式(Abstract Expression):声明一个抽象的解释操作,所有具体表达式都要实现这个接口。
- 终结符表达式(Terminal Expression):表示文法中的终结符,例如变量、常量等。
- 非终结符表达式(Non-terminal Expression):表示文法中的非终结符,也就是文法规则。
- 上下文(Context):包含解释器之外的一些全局信息。
- 解释器(Interpreter):实现文法中规定的解释操作。
以下是解释器模式的示例代码:
详情
// 抽象表达式
public interface Expression {
int interpret(Context context);
}
// 终结符表达式
public class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret(Context context) {
return number;
}
}
// 非终结符表达式
public class AddExpression implements Expression {
private Expression left;
private Expression right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) + right.interpret(context);
}
}
// 上下文
public class Context {
// 上下文中的一些全局信息
}
// 客户端
public class Client {
public static void main(String[] args) {
Context context = new Context();
Expression expression1 = new NumberExpression(10);
Expression expression2 = new NumberExpression(5);
Expression expression = new AddExpression(expression1, expression2);
int result = expression.interpret(context);
System.out.println("解释结果:" + result);
}
}
在解释器模式中,抽象表达式定义了一个抽象的解释操作,所有具体表达式都要实现这个接口。终结符表达式表示文法中的终结符,例如变量、常量等。非终结符表达式表示文法中的非终结符,也就是文法规则。上下文包含解释器之外的一些全局信息。解释器实现了文法中规定的解释操作。
解释器模式将语言的文法表示为一个类的层次结构,使得每个语言句子都可以被解释器对象解释执行。通过解释器模式,我们可以定义和扩展一种语言,使得它可以用来解析和执行特定的语句,从而实现复杂的业务逻辑。
需要注意的是,解释器模式在处理复杂的文法时可能会导致类的层次结构变得庞大和复杂。此外,解释器模式适用于对文法规则变动不频繁的情况,因为每次文法规则变动都需要修改解释器类的层次结构。因此,在使用解释器模式时,需要权衡灵活性和扩展性的问题,并确保适用于具体的应用场景。
状态模式
2023/8/8 10:54:09
2023/8/8 10:54:39
状态模式(State Pattern)是一种行为型设计模式,用于在对象内部定义一系列不同的状态,并封装每个状态对应的行为。通过动态改变对象的内部状态,使得对象在不同状态下具有不同的行为。
状态模式的核心思想是将对象的行为与其状态分离,将每个状态封装成一个独立的类,并使得这些状态类可以相互转换。对象内部维护一个当前状态的引用,根据当前状态来决定具体的行为。
状态模式的参与角色如下:
- 环境(Context):定义客户端所感兴趣的接口,并维护一个具体状态的引用。
- 抽象状态(State):定义一个接口或抽象类,用于封装与环境的特定状态相关的行为。
- 具体状态(Concrete State):实现抽象状态的接口或抽象类,具体定义与环境的特定状态相关的行为。
以下是状态模式的示例代码:
详情
// 环境
public class Context {
private State state;
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle();
}
}
// 抽象状态
public interface State {
void handle();
}
// 具体状态A
public class ConcreteStateA implements State {
@Override
public void handle() {
System.out.println("当前状态是A,执行A状态的行为");
}
}
// 具体状态B
public class ConcreteStateB implements State {
@Override
public void handle() {
System.out.println("当前状态是B,执行B状态的行为");
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Context context = new Context();
State stateA = new ConcreteStateA();
State stateB = new ConcreteStateB();
context.setState(stateA);
context.request();
context.setState(stateB);
context.request();
}
}
在状态模式中,环境定义了客户端所感兴趣的接口,并维护一个具体状态的引用。抽象状态定义了与环境的特定状态相关的行为,具体状态实现了抽象状态的接口或抽象类,具体定义了不同状态下的行为。
通过使用状态模式,可以使得对象的行为在运行时根据其内部状态的变化而变化,从而避免大量的条件判断语句。状态模式将状态的处理逻辑封装在状态类中,使得每个状态变得清晰明确,易于理解和修改。此外,状态模式还符合开闭原则,当需要增加新的状态时,只需新增一个具体状态类即可,无需修改已有的代码。
需要注意的是,状态模式适用于对象的行为与其状态密切相关的情况,当状态转换较为复杂时,使用状态模式可以简化代码结构,提高系统的可维护性和扩展性。
总结来说,状态模式通过将对象的行为与其状态分离,使得对象在不同状态下具有不同的行为。它是一种灵活、可扩展的设计模式,适用于需要根据内部状态改变行为的场景。
策略模式
2023/8/8 10:56:03
2023/8/8 10:56:32
策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列算法,并使它们可以相互替换,使得客户端能够独立于具体算法的变化。
策略模式的核心思想是将算法的定义和使用分离开来。通过将每个算法封装成一个独立的策略类,客户端可以根据需要选择合适的策略进行使用,从而实现不同算法之间的灵活切换。
策略模式的参与角色如下:
- 环境(Context):定义客户端所感兴趣的接口,并维护一个对策略对象的引用。
- 抽象策略(Strategy):定义一个接口或抽象类,用于封装具体算法的统一方法。
- 具体策略(Concrete Strategy):实现抽象策略的接口或抽象类,具体定义了不同的算法。
以下是策略模式的示例代码:
详情
// 环境
public class Context {
private Strategy strategy;
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.execute();
}
}
// 抽象策略
public interface Strategy {
void execute();
}
// 具体策略A
public class ConcreteStrategyA implements Strategy {
@Override
public void execute() {
System.out.println("执行策略A的算法");
}
}
// 具体策略B
public class ConcreteStrategyB implements Strategy {
@Override
public void execute() {
System.out.println("执行策略B的算法");
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Context context = new Context();
Strategy strategyA = new ConcreteStrategyA();
Strategy strategyB = new ConcreteStrategyB();
context.setStrategy(strategyA);
context.executeStrategy();
context.setStrategy(strategyB);
context.executeStrategy();
}
}
在策略模式中,环境定义了客户端所感兴趣的接口,并维护一个对策略对象的引用。抽象策略定义了具体算法的统一方法,每个具体策略类实现了抽象策略的接口或抽象类,并具体定义了不同的算法。
通过使用策略模式,可以将算法的定义和使用分离开来,使得客户端能够根据需要选择合适的策略进行使用。当需要增加新的算法时,只需新增一个具体策略类即可,无需修改已有的代码,符合开闭原则。
策略模式适用于存在多个相似算法但具体实现不同的情况,或者需要根据不同的条件选择不同的算法的情况。它可以提高代码的复用性、可扩展性和可维护性。
需要注意的是,策略模式要求客户端了解所有的策略,并主动进行策略的选择。如果策略的选择逻辑较为复杂,可以考虑结合其他模式来简化客户端的代码。另外,策略模式不适合用于频繁切换策略的情况,因为每次切换策略都需要修改环境的代码。
职责链模式
2023/8/8 10:57:50
2023/8/8 10:58:22
职责链模式(Chain of Responsibility Pattern)是一种行为型设计模式,用于将请求的发送者和接收者解耦,并通过一条链式结构来处理请求。
职责链模式的核心思想是:将多个处理器对象组成一条链,在链上传递请求,直到有一个处理器能够处理该请求为止。每个处理器对象负责判断自己是否能够处理请求,如果可以则进行处理,否则将请求传递给下一个处理器。这样可以实现请求的发送者和接收者之间的解耦,并且可以动态地改变请求的处理顺序。
职责链模式的参与角色如下:
- 抽象处理器(Handler):定义了处理请求的接口,并持有下一个处理器的引用。
- 具体处理器(Concrete Handler):实现了处理请求的方法,并在需要时调用下一个处理器。
以下是职责链模式的示例代码:
详情
// 抽象处理器
public abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handleRequest(Request request);
}
// 具体处理器A
public class ConcreteHandlerA extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getLevel() <= 10) {
System.out.println("ConcreteHandlerA 处理了请求:" + request.getContent());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
// 具体处理器B
public class ConcreteHandlerB extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getLevel() > 10 && request.getLevel() <= 20) {
System.out.println("ConcreteHandlerB 处理了请求:" + request.getContent());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
// 具体处理器C
public class ConcreteHandlerC extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getLevel() > 20 && request.getLevel() <= 30) {
System.out.println("ConcreteHandlerC 处理了请求:" + request.getContent());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
// 请求类
public class Request {
private int level;
private String content;
public Request(int level, String content) {
this.level = level;
this.content = content;
}
public int getLevel() {
return level;
}
public String getContent() {
return content;
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
Handler handlerC = new ConcreteHandlerC();
handlerA.setNextHandler(handlerB);
handlerB.setNextHandler(handlerC);
Request request1 = new Request(15, "请求1");
Request request2 = new Request(25, "请求2");
Request request3 = new Request(5, "请求3");
handlerA.handleRequest(request1);
handlerA.handleRequest(request2);
handlerA.handleRequest(request3);
}
}
在职责链模式中,每个具体处理器负责判断自己是否能够处理请求,如果可以则进行处理,否则将请求传递给下一个处理器。客户端只需要将请求发送给链的起始处理器,无需知道具体的处理器实现。
通过使用职责链模式,可以将请求的发送者和接收者解耦,并且可以动态地改变请求的处理顺序。当新增或修改处理器时,无需改变客户端的代码,符合开闭原则。此外,职责链模式还可以简化对象之间的直接引用关系,提高代码的灵活性和可维护性。
需要注意的是,职责链模式在处理请求时,可能会出现某些请求无法被处理的情况。因此,在设计职责链时需要合理安排每个处理器的处理逻辑和顺序,以确保所有请求都能得到处理。
访问者模式
2023/8/8 11:00:03
2023/8/8 11:00:36
访问者模式(Visitor Pattern)是一种行为型设计模式,用于在不改变已有对象结构的前提下,定义对这些对象的新操作。
访问者模式的核心思想是:将操作从被操作的对象中分离出来,定义在一个独立的访问者对象中。通过访问者对象的多态性,可以在不修改被操作的对象结构的情况下,对这些对象进行不同的操作。
访问者模式的参与角色如下:
- 抽象访问者(Visitor):声明了一系列访问方法,用于定义对各个具体元素的操作。
- 具体访问者(Concrete Visitor):实现了抽象访问者中定义的访问方法,即具体的操作逻辑。
- 抽象元素(Element):定义了接受访问者的方法,通过该方法可以让访问者访问自己。
- 具体元素(Concrete Element):实现了抽象元素中定义的接受访问者的方法,并根据需要进行自身状态的操作。
- 对象结构(Object Structure):包含了一组具体元素,并提供了遍历元素集合的方法。
以下是访问者模式的示例代码:
详情
// 抽象访问者
interface Visitor {
void visit(ElementA element);
void visit(ElementB element);
}
// 具体访问者A
class ConcreteVisitorA implements Visitor {
@Override
public void visit(ElementA element) {
System.out.println("具体访问者A访问" + element.operationA());
}
@Override
public void visit(ElementB element) {
System.out.println("具体访问者A访问" + element.operationB());
}
}
// 具体访问者B
class ConcreteVisitorB implements Visitor {
@Override
public void visit(ElementA element) {
System.out.println("具体访问者B访问" + element.operationA());
}
@Override
public void visit(ElementB element) {
System.out.println("具体访问者B访问" + element.operationB());
}
}
// 抽象元素
interface Element {
void accept(Visitor visitor);
}
// 具体元素A
class ElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
String operationA() {
return "具体元素A的操作";
}
}
// 具体元素B
class ElementB implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
String operationB() {
return "具体元素B的操作";
}
}
// 对象结构
class ObjectStructure {
private List<Element> elements = new ArrayList<>();
void attach(Element element) {
elements.add(element);
}
void detach(Element element) {
elements.remove(element);
}
void accept(Visitor visitor) {
for (Element element : elements) {
element.accept(visitor);
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.attach(new ElementA());
objectStructure.attach(new ElementB());
Visitor visitorA = new ConcreteVisitorA();
Visitor visitorB = new ConcreteVisitorB();
objectStructure.accept(visitorA);
objectStructure.accept(visitorB);
}
}
在访问者模式中,元素对象通过接受访问者对象来完成对自身的访问,而不同的具体访问者对象则可以实现不同的操作逻辑。通过将访问过程从元素对象中分离出来,使得新增访问操作时无需修改元素对象的代码,符合开闭原则。
需要注意的是,访问者模式一般适用于对象结构稳定,但其具体元素的操作经常变化的场景。如果对象结构经常变化,可能会导致访问者接口和具体元素类的频繁修改,降低了扩展性。
访问者模式可以提取出操作相对稳定的逻辑,并将其与元素对象分离,以达到解耦和增加灵活性的目的。它在编译器、解析器、符号表等复杂的数据结构处理上有广泛应用。