【设计模式二十三剑】✨编写更高质量代码的秘诀✨

✨✨简述

🎈设计模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样就能一次又一次地使用该方案而不必做重复劳动。核心在于提供了相关问题的解决方案,使得人们可以更加简单方便地复用成功的设计和体系结构
🎈设计模式是在软件工程中广泛使用的经过反复验证的解决方案,它们可以用来解决常见的设计问题。设计模式是对软件开发中经常出现的一些问题的一种通用解决方案,它们可以提高软件的可维护性、可重用性、灵活性和可扩展性。设计模式提供了一种通用的词汇和标准术语,使软件开发人员可以更加清晰地交流和理解软件设计和实现。同时,设计模式还可以加快软件开发过程,提高开发效率。

🎗设计模式的四个基本要素模式名称、问题、解决方案、效果

🎊🎊按照目的可以分为三类:

  • 创建型模式(Creational Patterns):主要关注对象的创建过程,包括如何实例化对象、如何组织对象的创建结构等。
  • 结构型模式(Structural Patterns):主要关注对象和类的组合方式,以及对象和类之间的组合方式。
  • 行为型模式(Behavioral Patterns):主要关注对象和类之间的通信方式,以及负责协调和控制类之间的交互。

在这里插入图片描述

==========================================================================================

🎆【万能之门】简单工厂模式(Simple Factory)

🎈简单工厂模式属于创建型模式,但不属于23种设计模式之一。
简单工厂模式可以通过一个工厂类创建不同的对象,就像开启了一个万能的门,可以制造出不同的产品。定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类 。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method) 模式,它属于类创建型模式

结构图如下:
在这里插入图片描述


🎗🎗有三类角色

  • Factory(工厂角色):简单工厂模式的核心,负责实现创建所有产品的内部逻辑,工厂类可以被外界直接调用,创建所需对象。
  • Product(抽象产品角色):工厂类所创建的所有对象的父类,封装了产品对象的公共方法,所有的具体产品为其子类对象。
  • ConcreteProduct(具体产品角色):简单工厂模式的创建目标,所有被创建的对象都是某个具体类的实力,它要实现抽象产品中声明的抽象方法。

代码实现:

public class SimpleFactory {
    public static void main(String[] args) {
        Product productA = Factory.createProduct("A");
        productA.info();
        
        Product productB = Factory.createProduct("B");
    }
}

// 抽象产品角色
abstract class Product {
    public abstract void info();
}

// 工厂角色
class Factory {
    public static Product createProduct(String type) {
        Product product = null;
        
        switch (type) {
            case "A":
                product = new ProductA();
                break;
            case "B":
                product = new ProductB();
                break;
            default:
                System.out.println("没有 " + type + " 类型的产品!");
                break;
        }
        
        return product;
    }
}

// 产品A
class ProductA extends Product {
    
    @Override
    public void info() {
        System.out.println("产品的信息:A");
    }
}

// 产品B
class ProductB extends Product {

    @Override
    public void info() {
        System.out.println("产品的信息:B");
    }
}

🎭优缺点:
【优点】
🧡 1、简单工厂模式将对象的创建过程集中在一个工厂类中,客户端无需知道具体的创建过程,只需要传递对应的参数即可创建对象,降低了客户端的复杂度和耦合度。
🧡 2、简单工厂模式可以根据不同的参数创建不同的对象,提高了代码的可扩展性和灵活性。
【缺点】
💚 1、简单工厂模式的工厂类通常包含了所有的对象创建逻辑,如果需要增加新的产品,则需要修改工厂类的代码,违反了开闭原则。
💚 2、工厂类负责创建所有的对象,当创建的对象过多时,工厂类会变得十分臃肿,难以维护。
💚 3、简单工厂模式的扩展性有限,无法应对复杂的业务需求。

==========================================================================================

🎇【制造之剑】工厂方法模式(Factory Method)

【刀光剑影,转瞬即逝,千变万化,百般精通。】

🎈 工厂方法模式是一种创建型设计模式,是简单工厂模式的延伸,它提供了一种将对象的实例化过程封装在子类中进行的方法。在工厂方法模式中,抽象工厂定义了一个创建对象的接口,由其具体子类来决定要实例化的类,而具体实例化的过程则延迟到具体子类中进行

工厂方法模式将对象的创建过程分离出来,使得客户端不需要知道具体的实现细节,只需要知道一个工厂接口即可,从而使系统更加灵活可扩展。

在工厂方法模式中,通常会定义一个抽象工厂接口和若干个具体的工厂类,每个工厂类负责创建一种具体的产品对象。同时,定义一个抽象产品接口和若干个具体的产品类,每个产品类负责实现具体的产品功能。客户端通过工厂接口来创建产品对象,不同的工厂实现类对应不同的产品对象。

结构图如下:
在这里插入图片描述


🥽 工厂方法模式适用于:

  • 当一个类不知道它所必须创建的对象的类的时候。
  • 当一个类希望由它的子类来指定它所创建的对象的时候。
  • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

代码实现:

public class FactoryMethod {
    public static void main(String[] args) {
        Factory factoryA = new FactoryA();
        // 父类 对象名 = new 子类();

        Product productA = factoryA.createProduct();
        // Product productA = new ProductA();
        productA.info();

        Factory factoryB = new FactoryB();

        Product productB = factoryB.createProduct();
        productB.info();
    }
}

// class Factory
interface Factory {
    public Product createProduct();
}

class FactoryA implements Factory {

    @Override
    public Product createProduct() {
        return new ProductA();
    }
}

class FactoryB implements Factory {

    @Override
    public Product createProduct() {
        return new ProductB();
    }
}

// abstract class Product
interface Product {
    // public abstract void info();
    public void info();
}

// class ProductA extends Product
class ProductA implements Product {

    @Override
    public void info() {
        System.out.println("产品的信息:A");
    }
}

// class ProductB extends Product
class ProductB implements Product {

    @Override
    public void info() {
        System.out.println("产品的信息:B");
    }
}

🎭优缺点:
【优点】
🧡 1、可以使系统更加灵活可扩展,可以动态地增加或修改产品类而不会影响到客户端代码。
🧡 2、符合“开闭原则”,即对扩展开放、对修改关闭,增加新的产品类只需要增加对应的工厂类即可,不需要修改原有代码。
🧡 3、降低了客户端和产品对象之间的耦合度,客户端只需要知道抽象工厂和抽象产品接口即可,具体的产品对象由具体的工厂类来创建。
🧡 4、工厂方法模式可以使用多态性,即客户端可以针对抽象工厂和抽象产品接口编程,而在运行时可以动态地替换具体的工厂类和产品类。
【缺点】
💚 1、需要定义大量的类,增加了系统的复杂度。
💚 2、工厂方法模式中的抽象产品类只能定义一些抽象的方法,而不能实现具体的功能,这限制了产品的功能扩展性。
💚 3、客户端需要知道具体工厂类的存在,这增加了客户端的使用难度。

==========================================================================================

🎇【生产之剑】抽象工厂模式(Abstract Factory)

【刀刃之上,锋芒毕露,不止于形,更注重意。】

🎈 抽象工厂模式是一种创建型设计模式,它提供了一种接口,可以创建一系列相关或相互依赖的对象,而无需指定它们的具体类。它是工厂方法模式的一种升级版,工厂方法模式只能创建一种类型的对象,而抽象工厂模式可以创建多个不同类型的对象。它可以帮助客户端隔离具体类的创建,同时提供了一种将系统的各个部分组合起来的方法。

抽象工厂模式通常包含一个抽象工厂类和多个具体工厂类,每个具体工厂类负责创建一组相关的产品对象。抽象工厂类定义了用于创建这些产品对象的接口,而具体工厂类则实现了这些接口。

抽象工厂模式的核心是抽象工厂类,该类定义了一系列用于创建产品的方法,这些方法通常被设计为抽象的,这样具体的工厂类就必须实现这些方法来创建具体的产品对象。另外,抽象工厂类也可以定义一些公共的方法和属性,用于描述所创建的产品对象的特性

结构图如下:

在这里插入图片描述

在这里插入图片描述


🥽抽象工厂模式适用于:

  • 一个系统要独立于它的产品创建、组合和表示时。
  • 一个系统要由多个产品系列中的一个来配置时。
  • 当要强调一系列相关的产品对象的设计以便进行联合使用时。
  • 当提供一个产品类库,只想显示它们的接口而不是实现时。

代码实现:

public class AbstractFactory {
    public static void main(String[] args) {
        Factory factory1 = new Factory1();

        ProductA productA = factory1.createProductA();
        productA.info();

        Factory factory2 = new Factory2();

        ProductB productB = factory2.createProductB();
        productB.info();
    }
}

interface Factory {
    public ProductA createProductA();
    public ProductB createProductB();
}

class Factory1 implements Factory {

    @Override
    public ProductA createProductA() {
        return new ProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new ProductB1();
    }
}

class Factory2 implements Factory {

    @Override
    public ProductA createProductA() {
        return new ProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new ProductB2();
    }
}

interface ProductA {
    public void info();
}

class ProductA1 implements ProductA {

    @Override
    public void info() {
        System.out.println("产品的信息:A1");
    }
}

class ProductA2 implements ProductA {

    @Override
    public void info() {
        System.out.println("产品的信息:A2");
    }
}

interface ProductB {
    public void info();
}

class ProductB1 implements ProductB {

    @Override
    public void info() {
        System.out.println("产品的信息:B1");
    }
}

class ProductB2 implements ProductB {

    @Override
    public void info() {
        System.out.println("产品的信息:B2");
    }
}

🎭优缺点:
【优点】
🧡 1、可以保证同一工厂生产出的产品系列是相互关联或相互依赖的。
🧡 2、抽象工厂模式使得产品的切换变得容易,只需要更改具体工厂即可。
🧡 3、可以使客户端代码与具体产品的实现分离,客户端代码只需要关心抽象产品的接口,而不需要关心具体产品的实现。
【缺点】
💚 1、抽象工厂模式的扩展性比较困难,因为抽象工厂接口中已经确定了可以创建的产品族,如果需要增加新的产品族,则需要修改抽象工厂接口,这样会影响到所有的具体工厂类。
💚 2、增加新的产品等级结构(即增加新的抽象产品和相应的具体产品)比较困难,因为需要修改所有的具体工厂类。

==========================================================================================

🎇【组装之剑】构造者模式(Builder)

【慧眼识珠,从零开始,耐心细致,打造完美。】

🎈 构造者模式是一种创建型设计模式,用于创建复杂对象。它提供一种分步骤创建对象的方法,使得同样的构建过程可以创建不同的表示

构造者模式的核心概念是将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示形式。它通过一个构造者类(Builder)来封装对象的构建过程,并提供一系列的方法来设置对象的属性或组件。然后,通过调用构造者类的方法,逐步构建对象,最终返回构建好的对象。

结构图如下:

在这里插入图片描述

在这里插入图片描述


🥽 构造者模式适用于:

  • 当构造过程必须允许被构造的对象有不同表示时。
  • 当创建复杂对象的算法,应独立于该对象的组成部分、以及组装方式时。

代码实现:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Director director = new Director();

        Builder builder1 = new Builder1();
        director.Construct(builder1);
        Product product1 = builder1.getResult();
        product1.show();

        Builder builder2 = new Builder2();
        director.Construct(builder2);
        Product product2 = builder2.getResult();
        product2.show();
    }
}

class Director {
    public void Construct(Builder builder) {
        builder.BuildPart();
    }
}

abstract class Builder {
    public abstract void BuildPart();
    public abstract Product getResult();
}

class Builder1 extends Builder {
    Product product = new Product();

    @Override
    public void BuildPart() {
        product.Add("A");
        product.Add("B");
        product.Add("C");
        product.Add("D");
        product.Add("E");
        product.Add("F");
    }

    @Override
    public Product getResult() {
        return product;
    }
}

class Builder2 extends Builder {
    Product product = new Product();

    @Override
    public void BuildPart() {
        product.Add("A");
        product.Add("B");
        product.Add("C");
    }

    @Override
    public Product getResult() {
        return product;
    }
}

class Product {
    List<String> parts = new ArrayList<String>();

    public void Add(String part) {
        parts.add(part);
    }

    public void show() {
        System.out.print("产品的组成:");
        for (String s : parts)
            System.out.print(s + " ");

        System.out.print("\n");
    }
}

🎭优缺点:
【优点】
🧡 1、封装复杂对象的构建过程:构造者模式将复杂对象的构建过程封装在一个独立的构造者类中,使得使用者无需关注对象的创建细节,只需通过简单的调用构造者的方法来构建对象。
🧡 2、可以创建不同表示的对象:通过调整构造者的步骤和顺序,可以创建具有不同属性配置的对象,满足不同的需求。这种灵活性使得构造者模式在创建复杂对象时非常有用。
🧡 3、提高代码的可读性和可维护性:由于构造者模式将对象的构建过程拆分为多个步骤,并通过方法链式调用的方式进行配置,使得代码更加清晰、易读,也更易于维护和扩展。
🧡 4、逐步构建对象:构造者模式支持逐步构建对象,每一步都可以设置对象的属性或组件。这种逐步构建的方式使得构建过程更加灵活,可以根据需要动态调整对象的属性。
【缺点】
💚 1、增加了代码量:构造者模式引入了额外的构造者类,增加了代码量和类的数量。对于简单的对象创建,使用构造者模式可能会显得过于繁琐。
💚 2、增加了系统的开销:由于构造者模式要求逐步构建对象,可能会增加系统的开销。如果对象的创建过程简单且固定,使用构造者模式可能会显得冗余。
💚 3、不适用于创建不可变对象:构造者模式通常用于创建可变对象,如果需要创建不可变对象,可能需要额外的处理来保证对象的不可变性。

==========================================================================================

🎇【复制之剑】原型模式(Prototype)

【一招制敌,快速无比,复制无限,造就全新。】

🎈 原型模式是一种创建型设计模式,它允许通过复制(克隆)现有对象来创建新对象,而无需显式地使用构造函数。该模式基于一个原型对象,通过复制该原型对象的属性和状态来创建新的对象实例,从而实现对象的复制和创建。

原型模式的核心思想是将对象的创建委托给原型对象,原型对象作为一个可复制的模板,定义了对象的结构和初始状态。通过克隆原型对象,可以创建出与原型相同的新对象,而且新对象的创建过程可以根据需要进行定制和扩展。

结构图如下:
在这里插入图片描述

在这里插入图片描述


🥽 原型模式适用于:

  • 一个系统要独立于它的产品的创建、构成和表示时。
  • 当要实例化的类是在运行时刻指定时,例如,通过动态装载。
  • 为了避免创建一个与产品类层次平行的工厂类层次时。
  • 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们,可能比每次用合适的状态手工实例化该类更方便一些。

代码实现:

public class Main {
    public static void main(String[] args) {
        Product product1 = new Product(2022, 5.28);
        System.out.println(product1.getId() + " " + product1.getPrice());

        // Product product2 = new Product(2022, 5.28);
        Product product2 = (Product) product1.Clone();
        System.out.println(product2.getId() + " " + product2.getPrice());

        Product product3 = (Product) product1.Clone();
        System.out.println(product3.getId() + " " + product3.getPrice());
    }
}

interface Prototype {
    public Object Clone();
}

class Product implements Prototype {
    private int id;
    private double price;

    public Product() {}

    public Product(int id, double price) {
        this.id = id;
        this.price = price;
    }

    public int getId() {
        return id;
    }

    public double getPrice() {
        return price;
    }

    @Override
    public Object Clone() {
        Product object = new Product();
        object.id = this.id;
        object.price = this.price;

        return object;
    }
}

🎭优缺点:
【优点】
🧡 1、简化对象创建:原型模式通过克隆原型对象来创建新对象,避免了使用复杂的构造函数进行对象初始化的过程,使对象创建变得简单和直观。
🧡 2、提高性能:与直接创建对象相比,克隆原型对象可以提高对象创建的速度,避免了重复的初始化过程,特别是对于创建开销较大的对象而言,性能的提升更为显著。
🧡 3、实现对象定制化:原型模式允许动态地添加或修改原型对象的属性和行为,通过修改原型对象的克隆结果,可以实现对象的个性化定制。
【缺点】
💚 1、克隆对象的复杂性:某些对象的克隆可能涉及到引用类型属性的处理,需要特别注意对象的引用关系和克隆的深浅复制问题。复杂对象的克隆可能会增加代码的复杂性。
💚 2、内存消耗:原型模式需要在内存中保存原型对象,当需要大量创建对象时,会增加内存消耗。特别是深克隆的情况下,可能会占用更多的内存空间。
💚 3、克隆与继承的冲突:在某些语言中,原型模式与继承机制存在冲突,因为克隆对象是通过复制已有对象来创建的,而不是通过继承父类来创建。

==========================================================================================

🎇【孤独之剑】单例模式(Singleton)

【独行无比,孤身一剑,随时为我所用。】

🎈 单例模式是一种创建型设计模式,它确保一个类只有一个实例对象,并提供全局访问点。

在单例模式中,类的构造函数被私有化,防止外部代码直接实例化对象。而通过定义一个静态方法或静态变量,让类自身负责创建并管理唯一的实例对象。每次调用该静态方法时,都返回同一个实例对象。

结构图如下:
在这里插入图片描述


🥽单例模式适用于:

  • 当类只能有一个实例而且客户可以从一个 从所周知的访问点访问它时。
  • 当这个唯一实例应该是通过子类化可扩展的,并且客户无须更改代码就能使用一个扩展的实例时。

代码实现:

public class SingletonPattern {
    public static void main(String[] args) {
        // Singleton singleton1 = new Singleton();

        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        Singleton singleton3 = Singleton.getInstance();

        System.out.println(singleton1.getNumber() + " " + singleton2.getNumber() + " " + singleton3.getNumber());

        singleton1.setNumber(528);
        System.out.println(singleton1.getNumber() + " " + singleton2.getNumber() + " " + singleton3.getNumber());

    }
}

class Singleton {
    private int number = 2022;

    public void setNumber(int number) {
        this.number = number;
    }

    public int getNumber() {
        return number;
    }

    private static Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}

🎭优缺点:
【优点】
🧡 1、确保只有一个实例:单例模式保证类只有一个实例对象,避免了多次实例化的开销和资源浪费。
🧡 2、全局访问点:通过单例模式,可以在程序的任何位置访问该实例对象,方便地共享和调用。
🧡 3、避免竞态条件:在多线程环境下,单例模式可以防止多个线程同时创建实例对象,避免了竞态条件和数据不一致的问题。
【缺点】
💚 1、难以扩展和测试:因为单例模式将实例对象的创建和管理集中在类内部,对于扩展和测试来说可能会变得更加困难。
💚 2、违反单一职责原则:单例模式负责创建和管理实例对象,可能导致类的职责不够清晰,违反了单一职责原则。

==========================================================================================

🎍【调和之剑】适配器模式(Adapter)

【智勇双全,神机妙算,从不屈服,化难为易。】

🎈 适配器模式是一种结构型设计模式,用于将一个类的接口转换成另一个接口,使得不兼容的类能够一起工作

适配器模式的核心概念是适配器(Adapter),它充当两个不兼容类之间的桥梁。适配器接受一个类的请求,并将其转换为另一个类可以理解的格式。

结构图如下:
在这里插入图片描述

在这里插入图片描述


🥽适配器模式适用于:

  • 想使用一个已经存在的类,而它的接口不符合要求。

将Type-C接口通过适配器插入到USB接口

在这里插入图片描述

代码实现:

public class AdapterPattern {
    public static void main(String[] args) {
        USB usb = new Adapter();
        usb.Request();
    }
}

class USB {
    public void Request() {
        System.out.println("USB数据线");
    }
}

class Adapter extends USB {
    private TypeC typeC = new TypeC();

    @Override
    public void Request() {
        typeC.SpecificRequest();
    }
}

class TypeC {
    public void SpecificRequest() {
        System.out.println("Type-C数据线");
    }
}

🎭优缺点:
【优点】
🧡 1、适配多个适配者类:对象型适配器模式可以适配多个适配者类,不受单一继承的限制,提高了代码的灵活性和复用性。
🧡 2、解耦性强:适配器类将适配者对象和客户端代码分离,使得它们可以独立演化,降低了它们之间的依赖关系。
🧡 3、可以动态改变适配者对象:对象型适配器模式允许在运行时更换适配者对象,实现动态适配。
【缺点】
💚 1、增加了系统的复杂性:引入适配器类增加了系统的组件和结构,使得系统更加复杂,增加了理解和维护的难度。
💚 2、增加了开发工作量:对象型适配器模式需要额外编写适配器类,增加了开发工作量和代码量。
💚 3、适配器功能局限性:适配器类的功能受限于适配者类的接口,如果适配者类的接口发生变化,适配器类需要相应地进行修改。

==========================================================================================

🎍【联通之剑】桥接模式(Bridge)

【高屋建瓴,跨越重深,无所不能,纵横天下。】

🎈 桥接模式是一种结构型设计模式,它将抽象部分和实现部分分离,使它们可以独立地变化。桥接模式通过将抽象和实现之间的耦合关系转移到一个桥接类中,从而实现了抽象和实现的解耦。

桥接模式中,抽象部分定义了抽象接口,包含了对实现部分的引用,而实现部分则提供了具体的实现。桥接模式通过在抽象部分和实现部分之间建立一个桥接来连接它们。这样,抽象部分和实现部分可以独立地扩展和变化,而不会相互影响。

结构图如下:

在这里插入图片描述

在这里插入图片描述


🥽桥接模式适用于:

  • 不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如,这种情况可能是因为,在程序运行时刻实现部分应可以被选择或者切换。
  • 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这是Bridge模式使得开发者可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。
  • 对一个抽象的实现部分的修改应对客户不产生影响,即客户代码不必重新编译。

代码实现:

public class BridgePattern {
    public static void main(String[] args) {
        Product productA1 = new ProductA();
        Product productA2 = new ProductA();
        Color red = new Red();

        productA1.setName("产品A1");
        productA1.setColor(red);
        productA1.Operation();


        Blue blue = new Blue();
        productA2.setName("产品A2");
        productA2.setColor(blue);
        productA2.Operation();
    }
}

abstract class Product {
    private String name;
    protected Color color;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public abstract void Operation();
}

class ProductA extends Product {

    @Override
    public void Operation() {
        color.OperationImp(this.getName());
    }
}

interface Color {
    public void OperationImp(String name);
}

class Red implements Color {

    @Override
    public void OperationImp(String name) {
        System.out.println(name + ":红色");
    }
}

class Blue implements Color {

    @Override
    public void OperationImp(String name) {
        System.out.println(name + ":蓝色");
    }
}

🎭优缺点:
【优点】
🧡 1、解耦抽象和实现:桥接模式将抽象部分和实现部分分离,使它们可以独立地变化和演化,减少它们之间的耦合度。
🧡 2、可扩展性:由于抽象部分和实现部分可以独立地扩展,因此可以更灵活地增加新的抽象和实现,而不会影响现有的代码结构。
🧡 3、改善可维护性:桥接模式使得系统的结构更清晰,代码更易于理解和维护,减少了复杂性。
🧡 4、提高了系统的灵活性:通过桥接模式,可以动态地切换和组合抽象和实现的部分,使系统更具灵活性。
【缺点】
💚 1、增加了系统的复杂性:桥接模式引入了抽象和实现之间的桥接类,增加了额外的类和接口,使系统结构复杂化。
💚 2、增加了开发的工作量:桥接模式需要定义抽象接口、实现接口和桥接类,增加了开发的工作量。
💚 3、不适用于简单系统设计:对于简单的系统设计,桥接模式可能会显得过于繁琐,不适合使用。

==========================================================================================

🎍【合力之剑】组合模式(Composite)

【天人合一,刚柔并济,兼收并蓄,合纵连横。】

🎈 组合模式是结构型设计模式之一,通过将对象组合成树形结构来表示整体-部分的层次关系,使得用户对单个对象和组合对象的使用具有一致性

例如:文件系统的树形结构
在这里插入图片描述

结构图如下:

在这里插入图片描述

  • 抽象构件(Component)角色:这是一个抽象角色,它给参加组合的对象定义出公共的接口及其默认行为,可以用来管理所有的子对象。合成对象通常把它所包含的子对象当做类型为Component的对象。构件角色并不定义出管理子对象的方法,这一定义由树枝构件对象给出。
  • 树叶构件(Leaf)角色:树叶对象是没有下级子对象的对象,定义出参加组合的原始对象的行为。
  • 树枝构件(Composite)角色:代表参加组合的有下级子对象的对象。树枝构件类给出所有的管理子对象的方法,如Add()、Remove()以及GetChild()。

🥽组合模式适用于:

  • 想表示对象的部分-整体层次结构。
  • 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

代码实现:

import java.util.*;

public class CompositePattern {
    public static void main(String[] args) {
        // 父类名 对象名 = new 子类名();
        AbstractFile root = new Folder("root");

        AbstractFile folderA = new Folder("folderA");
        AbstractFile folderB = new Folder("folderB");

        AbstractFile fileC = new File("fileC");
        AbstractFile fileD = new File("fileD");
        AbstractFile fileE = new File("fileE");

        root.Add(folderA);
        root.Add(folderB);
        root.Add(fileC);

        folderA.Add(fileD);
        folderA.Add(fileE);

        print(root);
    }

    static void print(AbstractFile file) {
        file.printName();

        List<AbstractFile> childrenList = file.getChildren();
        if (childrenList == null) return;

        // for (对象类型 对象名 : 遍历对象)
        for (AbstractFile children : childrenList) {
            // children.printName();
            print(children);
        }
    }
}

abstract class AbstractFile {
    protected String name;

    public void printName() {
        System.out.println(name);
    }

    public abstract boolean Add(AbstractFile file);
    public abstract boolean Remove(AbstractFile file);
    public abstract List<AbstractFile> getChildren();
}

class Folder extends AbstractFile {
    private List<AbstractFile> childrenList = new ArrayList<AbstractFile>();

    public Folder(String name) {
        this.name = name;
    }

    @Override
    public boolean Add(AbstractFile file) {
        return childrenList.add(file);
    }

    @Override
    public boolean Remove(AbstractFile file) {
        return childrenList.remove(file);
    }

    @Override
    public List<AbstractFile> getChildren() {
        return childrenList;
    }
}

class File extends AbstractFile {
    public File(String name) {
        this.name = name;
    }

    @Override
    public boolean Add(AbstractFile file) {
        return false;
    }

    @Override
    public boolean Remove(AbstractFile file) {
        return false;
    }

    @Override
    public List<AbstractFile> getChildren() {
        return null;
    }
}

🎭优缺点:
【优点】

🧡 1、简化客户端代码:组合模式统一了对单个对象和组合对象的处理,使得客户端代码更加简洁,无需对对象的类型进行区分。
🧡 2、灵活的对象组织:组合模式可以灵活地组织和管理对象的层次结构,可以动态地增加、删除和修改对象,而无需修改客户端代码。
🧡 3、递归处理对象:组合模式适用于对复杂结构的递归处理,可以以统一的方式对整体和部分对象进行操作和遍历。
🧡 4、清晰的表示整体-部分关系:组合模式提供了一种简洁明了的方式来表示对象的整体-部分关系,使得代码更加清晰和易于理解。
【缺点】
💚 1、增加了系统的复杂性:组合模式引入了组合对象和叶子对象之间的层次关系,增加了系统的复杂性,需要在设计和实现时考虑层次结构的管理和维护。
💚 2、可能导致设计过度:如果对象结构并不复杂,或者不需要对整体和部分对象进行一致的操作,使用组合模式可能会导致设计过度,增加不必要的复杂性。

==========================================================================================

🎍【加持之剑】装饰器模式(Decorator)

【瑕不掩瑜,美轮美奂,点缀画龙,精雕细琢。】

🎈 装饰器模式是一种结构型设计模式,它允许动态地给一个对象添加额外的职责,同时又不改变其原有的接口。装饰器模式通过包装原始对象,可以在运行时动态地添加、修改或删除对象的行为。就增加功能而言,装饰器模式比生成子类更加灵活。

结构图如下:

在这里插入图片描述

  • Component 定义一个对象接口,可以给这些对象动态地添加职责。
  • ConcreteComponent 定义一个对象,可以给这个对象添加一些职责。
  • Decorator 维持一个指向 Component 对象的指针,并定义一个与 Component 接口一致的接口。
  • ConcreteDecorator 向组件添加职责。

🥽装饰器模式适用于:

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 处理那些可以撤销的职责。

代码实现:

public class DecoratorPattern {
    public static void main(String[] args) {
        Person zhangsan = new Student("张三");
        zhangsan = new DecoratorA(zhangsan);
        zhangsan = new DecoratorB(zhangsan);
        zhangsan.Operation();

        System.out.println("\n=====我是分割线=====");

        // 对象链
        Person lisi = new DecoratorB(new DecoratorA(new Student("李四")));
    }
}

abstract class Decorator extends Person {
    protected Person person;
}

class DecoratorA extends Decorator {
    public DecoratorA(Person person) {
        this.person = person;
    }

    @Override
    public void Operation() { // 职责
        person.Operation(); // 原本的职责
        System.out.print("写作业 ");
    }
}

class DecoratorB extends Decorator {
    public DecoratorB(Person person) {
        this.person = person;
    }

    @Override
    public void Operation() { // 职责
        person.Operation(); // 原本的职责
        System.out.print("考试 ");
    }
}

abstract class Person {
    protected String name;

    public abstract void Operation(); // 职责
}

class Student extends Person {
    public Student(String name) {
        this.name = name;
    }

    @Override
    public void Operation() {
        System.out.print(name + "的职责:学习 ");
    }
}

🎭优缺点
【优点】
🧡 1、动态扩展功能:装饰器模式允许在运行时动态地添加、修改或删除对象的行为,而无需修改原始对象的代码。
🧡 2、遵循开闭原则:通过装饰器模式,可以通过扩展装饰器类来增加新的功能,而不需要修改已有的代码,符合开闭原则。
🧡 3、组合灵活性:可以通过组合多个装饰器对象来实现对对象功能的叠加,灵活地组合出所需的功能。
【缺点】
💚 1、增加复杂性:引入了多个具体装饰器类和抽象组件类,增加了系统的复杂性。
💚 2、可能产生过多的对象:每个装饰器对象都需要包装一个抽象组件对象,可能导致系统中对象的数量增加。

==========================================================================================

🎍【掌控之剑】外观模式(Facade)

【一览众山小,开门见山,千变万化,尽显奇妙。】

🎈 外观模式是一种结构型设计模式,它为子系统中的一组接口提供一个一致的界面。外观模式隐藏了子系统的复杂性,为客户端提供了一个简单的接口,使得客户端不需要了解子系统的具体实现细节。

结构图如下:
在这里插入图片描述

  • Facade 知道哪些子系统类负责处理请求;将客户的请求代理给适当的子系统对象。
  • Subsystem classes 实现子系统的功能;处理有 Facade 对象指派的任务;没有 Facade 的任何相关信息,即没有指向 Facade 的指针。

🥽外观模式适用于:

  • 要为一个复杂子系统提供一个简单接口时。
  • 客户程序与抽象类的实现部分之间存在着很大的依赖性。
  • 当需要构建一个层次结构的子系统时,使用 Facade 模式定义子系统中每层的入口点。

代码实现:

public class FacadePattern {
    public static void main(String[] args) {
        Facade facade = new Facade();

        facade.methodA();
        facade.methodB();
        facade.methodC();
    }
}

class Facade {
    SubSystemOne subSystemOne;
    SubSystemTwo subSystemTwo;
    SubSystemThree subSystemThree;

    public Facade() {
        subSystemOne = new SubSystemOne();
        subSystemTwo = new SubSystemTwo();
        subSystemThree = new SubSystemThree();
    }

    public void methodA() {
        subSystemOne.methodOne();
    }

    public void methodB() {
        subSystemTwo.methodTwo();
    }

    public void methodC() {
        subSystemThree.methodThree();
    }
}

class SubSystemOne {
    public void methodOne() {
        System.out.println("执行子系统一的功能");
    }
}

class SubSystemTwo {
    public void methodTwo() {
        System.out.println("执行子系统二的功能");
    }
}

class SubSystemThree {
    public void methodThree() {
        System.out.println("执行子系统三的功能");
    }
}

🎭优缺点
【优点】
🧡 1、简化接口:外观模式提供了一个简单的接口,隐藏了子系统的复杂性,使得客户端更加容易使用。
🧡 2、解耦子系统和客户端:外观模式将子系统与客户端解耦,使得它们可以独立地进行演化和修改,不会相互影响。
🧡 3、提高了代码的可维护性:外观模式将子系统的接口封装在一个外观对象中,使得系统的结构更加清晰,代码更加易于理解和维护。
【缺点】
💚 1、违反了开闭原则:如果需要添加新的子系统或修改现有子系统,可能需要修改外观对象的代码,违反了开闭原则。
💚 2、可能引入了额外的复杂性:如果外观对象变得过于庞大或复杂,可能会影响到系统的性能和可维护性。

==========================================================================================

🎍【共享之剑】享元模式(Flyweight)

【繁而不乱,大而不倒,各尽其能,共享荣华。】

🎈 享元模式是一种结构型设计模式,它旨在通过共享对象来减少内存使用和提高性能。享元模式通过将对象的状态划分为内部状态和外部状态,将共享的内部状态存储在享元对象中,而将不同的外部状态作为参数传递给享元对象的方法,从而实现对象的共享。

结构图如下:
在这里插入图片描述
在这里插入图片描述


🥽享元模式适用于:

  • 一个应用程序使用了大量的对象。
  • 完全由于使用大量的对象,造成很大的存储开销。
  • 对象的大多数状态都可变为外部状态。
  • 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
  • 应用程序不依赖于对象标识。

代码实现:

import java.util.*;

public class FlyWeightPattern {
    public static void main(String[] args) {
        ShapeFactory factory = new ShapeFactory();

        Random random = new Random();
        String[] colors = {"red", "blue", "green", "white", "black"};

        for (int i = 1; i <= 100; i ++ ) {
            int x = random.nextInt(colors.length); // [0 ~ 4]
            Shape shape = factory.getShape(colors[x]);

            System.out.print("第" + i + "个圆:");
            shape.draw(random.nextInt(2022), random.nextInt(528));
        }
    }
}

class ShapeFactory {
    private Map<String, Shape> map = new HashMap<String, Shape>();

    public Shape getShape(String key) {
        if (!map.containsKey(key)) {
            map.put(key, new Circle(key));
            System.out.println("create color:" + key + " circle");
        }

        return map.get(key);
    }
}

abstract class Shape {
    protected String color;

    public abstract void draw(int x, int y);
}

class Circle extends Shape {
    public Circle(String color) {
        this.color = color;
    }

    @Override
    public void draw(int x, int y) {
        System.out.println("draw a color:" + color + " circle x:" + x + " y:" + y);
    }
}

🎭优缺点
【优点】
🧡 1、减少内存使用:通过共享内部状态,减少了对象的创建数量,降低了内存的消耗。
🧡 2、提高性能:共享对象可以被多个客户端共享和重用,减少了对象的创建和销毁操作,提高了系统的性能。
🧡 3、简化对象结构:享元模式将对象的状态划分为内部状态和外部状态,使对象结构更加简单和清晰。
【缺点】
💚 1、增加了系统复杂性:为了实现对象的共享和外部状态的传递,需要引入额外的逻辑,增加了系统的复杂性。
💚 2、对象共享可能导致线程安全问题:如果多个线程同时修改享元对象的外部状态,可能导致线程安全问题,需要进行适当的同步处理。

==========================================================================================

🎍【护卫之剑】代理模式(Proxy)

【守护无微不至,身影卓然,内外兼备,确保安全可靠。】

🎈 代理模式是一种结构型设计模式,它允许通过创建一个代理对象来控制对原始对象的访问。代理模式可以提供额外的功能,同时隐藏了原始对象的复杂性。

结构图如下:

在这里插入图片描述

  • 抽象主题(Subject):定义了代理和真实主题对象共同实现的接口,这样代理对象可以替代真实主题对象被客户端使用。
  • 真实主题(RealSubject):定义了代理对象所代表的真实对象。
  • 代理(Proxy):持有一个真实主题对象的引用,实现了抽象主题接口,并可以控制或扩展真实主题对象的访问。

🥽代理模式适用于:

在这里插入图片描述


代码实现:

public class ProxyPattern {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        Proxy proxy = new Proxy(realSubject);

        proxy.buy();
    }
}

interface Subject {
    public void buy();
}

class Proxy implements Subject {
    protected RealSubject realSubject;

    public Proxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void buy() {
        System.out.println("办理购买前的手续");
        realSubject.buy(); // 付钱
        System.out.println("办理购买后的手续");
    }
}

class RealSubject implements Subject {

    @Override
    public void buy() {
        System.out.println("付钱");
    }
}

🎭优缺点
【优点】
🧡 1、职责分离:代理模式可以将真实对象和代理对象的职责进行分离,使得代理对象可以独立处理一些与真实对象无关的事务,增强了系统的可扩展性和灵活性。
🧡 2、高效性:通过使用代理模式,可以在访问真实对象前后添加额外的处理逻辑,例如缓存数据、权限控制、日志记录等,从而提高系统的性能和效率。
🧡 3、隐藏真实对象:代理对象可以隐藏真实对象的具体实现细节,使得客户端只需要与代理对象进行交互,无需直接访问真实对象,增强了系统的安全性。
🧡 4、懒加载:代理模式中的延迟加载可以在真正需要使用真实对象时才进行实例化,可以节省系统资源。
【缺点】
💚 1、增加复杂性:引入代理对象会增加系统的复杂性,需要额外的代码来管理代理对象和真实对象之间的关系。
💚 2、增加响应时间:由于代理模式引入了额外的间接层,可能会增加系统的响应时间,特别是当代理对象需要执行一些复杂的操作时。
💚 3、可能会降低效率:在某些情况下,代理模式可能会导致系统的运行效率降低,例如频繁创建和销毁代理对象。

==========================================================================================

🎨【承载之剑】责任链模式(Chain of Responsibility)

【源远流长,承前启后,职责交织,使命传承。】

🎈 责任链模式是一种行为设计模式,用于解耦发送者和接收者之间的关系。在责任链模式中,多个对象按照顺序连接在一起,每个对象都有处理请求的机会,但并不保证每个对象都能处理请求。请求沿着对象链依次传递,直到有一个对象能够处理它为止。

在责任链模式中,每个对象都有一个指向下一个对象的引用,形成一个链条。当请求到达一个对象时,该对象可以选择处理请求、转发请求给下一个对象或者将请求传递给链条的末尾。这样,请求可以在链条中传递,直到被处理或者到达链条的末尾。

结构图如下:在这里插入图片描述

  • Handler 定义一个处理请求的接口;实现后继链。
  • ConcreteHandler 处理它所负责的请求;可访问它的后继者;如果可处理该请求,就处理它,否则将该请求转发给后继者。
  • Client 向链上的具体处理者(ConcreteHandler )对象提交请求。

🥽责任链模式适用于:

  • 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
  • 想在不明确指定接受者的情况下向多个对象中的一个提交一个请求。
  • 可处理一个请求的对象集合应被动态指定。

代码实现:

// 责任链模式审批请假情况
public class ChainOfResponsibilityPattern {
    public static void main(String[] args) {
        Handler fudaoyuan = new FuDaoYuan();
        Handler yuanzhang = new YuanZhang();
        Handler xiaozhang = new XiaoZhang();

		// 责任链:辅导员->院长->校长
        fudaoyuan.setNext(yuanzhang);
        yuanzhang.setNext(xiaozhang);

        fudaoyuan.HandlerRequest(31);
    }
}

abstract class Handler {
    protected Handler next;

    public void setNext(Handler next) {
        this.next = next;
    }

    public abstract void HandlerRequest(int request);
}

class FuDaoYuan extends Handler { // <= 7 审批

    @Override
    public void HandlerRequest(int request) {
        if (request <= 7) {
            System.out.println("辅导员审批通过");
        } else {
            if (next != null) {
                next.HandlerRequest(request);
            } else {
                System.out.println("无法审批");
            }
        }
    }
}

class YuanZhang extends Handler { // <= 15 审批

    @Override
    public void HandlerRequest(int request) {
        if (request <= 15) {
            System.out.println("院长审批通过");
        } else {
            if (next != null) {
                next.HandlerRequest(request);
            } else {
                System.out.println("无法审批");
            }
        }
    }
}

class XiaoZhang extends Handler { // <= 30 审批

    @Override
    public void HandlerRequest(int request) {
        if (request <= 30) {
            System.out.println("校长审批通过");
        } else {
            if (next != null) {
                next.HandlerRequest(request);
            } else {
                System.out.println("无法审批");
            }
        }
    }
}

🎭优缺点
【优点】
🧡 1、解耦发送者和接收者:责任链模式将请求的发送者和接收者解耦,使得它们不需要直接知道彼此的存在,从而降低了它们之间的耦合度。
🧡 2、灵活性和可扩展性:责任链模式允许动态地增加或修改处理请求的对象,可以根据实际需求灵活地调整链条结构。这使得系统更加灵活,易于扩展和维护。
🧡 3、可以动态改变请求处理顺序:责任链模式允许在运行时动态地改变请求处理的顺序,可以根据不同的条件或规则调整处理链条,以适应不同的业务需求。
🧡 4、可以处理复杂的请求处理逻辑:由于责任链模式将请求分散到多个处理者中,每个处理者只关注自己能够处理的请求,因此可以处理复杂的请求处理逻辑,将大问题拆分成多个小问题,使得代码更加清晰和可维护。
【缺点】
💚 1、请求的处理不保证被接收:由于责任链模式中的每个处理者都有可能处理或者转发请求,因此并不能保证每个请求都会被接收和处理。这可能导致一些请求没有得到处理,或者在链条末尾没有找到合适的处理者。
💚 2、性能影响:责任链模式的请求需要在整个链条中传递,直到被处理或者到达链条末尾。如果链条过长或者处理者过多,可能会对系统性能产生一定的影响。
💚 3、可能导致循环引用或死循环:如果责任链没有正确配置,可能会导致循环引用或死循环的问题,请求在链条中不断循环传递,无法正常结束。

==========================================================================================

🎨【掌舵之剑】命令模式(Command)

【号令如山,指挥有方,调动全局,运筹帷幄。】

🎈 命令模式是一种行为设计模式,它将请求封装为一个对象,从而使得可以使用不同的请求来参数化客户端对象,将请求的发送者和接收者解耦;对请求排队或记录请求日志,以及支持可撤销的操作。

结构图如下:

在这里插入图片描述
在这里插入图片描述


🥽 命令模式适用于:

  • 抽象出待执行的动作以参数化某对象。
  • 在不同时刻指定、排列和执行请求。
  • 支持取消操作。
  • 支持修改日志。

代码实现:

public class CommandPattern {
    public static void main(String[] args) {
        Tv tv = new Tv(); // 接收者 对象 电视机

        Command onCommand = new OnCommand(tv); // 命令对象 开机命令
        Command offCommand = new OffCommand(tv); // 命令对象 关机命令

        Invoker invoker = new Invoker(); // 请求者
        invoker.setCommand(onCommand); // 给请求者设置 开机 命令
        invoker.call(); // 请求者去请求命令

        System.out.println("========================================");

        invoker.setCommand(offCommand); // 给请求者设置 关机命令
        invoker.call(); // 请求者去请求命令
    }
}

class Invoker { // 请求者
    private Command command; // 命令

    public void setCommand(Command command) { // 设置请求者 的 请求的命令
        this.command = command;
    }

    public void call() { // 调用
        command.Execute();
    }
}

interface Command { // 命令接口
    public void Execute(); // 执行命令
}

class OnCommand implements Command { // 开机命令
    private Tv tv;

    public OnCommand(Tv tv) {
        this.tv = tv;
    }

    @Override
    public void Execute() {
        tv.OnAction();
    }
}

class OffCommand implements Command { // 关机命令
    private Tv tv;

    public OffCommand(Tv tv) {
        this.tv = tv;
    }

    @Override
    public void Execute() {
        tv.OffAction();
    }
}

class Tv { // 接收者 电视机
    public void OnAction() { // 开机行为
        System.out.println("电视机开机了...");
    }

    public void OffAction() { // 关机行为
        System.out.println("电视机关机了...");
    }
}

🎭 优缺点
【优点】
🧡 1、解耦发送者和接收者:命令模式将发送者和接收者解耦,使得它们不需要直接交互,降低了系统的耦合度。
🧡 2、容易扩展和维护:由于命令模式将请求封装成对象,因此可以方便地新增或修改命令对象,而不影响其他部分的代码。
🧡 3、支持撤销和重做:命令对象可以记录操作的历史,支持撤销和重做操作。
🧡 4、支持队列和日志:可以将命令对象放入队列中进行排队处理,或者将命令操作记录到日志中。
【缺点】
💚 1、类数量增加:引入命令对象会增加类的数量,特别是在有大量命令操作的情况下,可能会导致类的膨胀。
💚 2、代码复杂性增加:命令模式需要定义多个类和接口,可能会增加代码的复杂性。

==========================================================================================

🎨【解谜之剑】解释器模式(Interpreter)

【义理分明,言简意赅,层层深入,见微知著。】

🎈 解释器模式是一种行为设计模式,它用于解决特定问题的语言解释和执行。该模式定义了一个语言的文法,并通过解释器来解释和执行语言中的句子

结构图如下:

在这里插入图片描述
在这里插入图片描述


🥽 解释器模式适用于:

在这里插入图片描述


代码实现:

import java.util.*;

public class InterpreterPattern {
    public static void main(String[] args) {
        Context context = new Context();

        context.check("A区的开发人员");
        context.check("B区的调试人员");
        context.check("C区的测试人员");

        System.out.println("==========");

        context.check("D区的程序员");
        context.check("D区的测试员");
        context.check("A区的程序员");
    }
}

class Context {
    private String[] regions = {"A区", "B区", "C区"};
    private String[] persons = {"开发人员", "测试人员", "调试人员"};

    private NonterminalExprssion nonterminal;

    public Context() {
        TerminalExpression region = new TerminalExpression(regions);
        TerminalExpression person = new TerminalExpression(persons);
        nonterminal = new NonterminalExprssion(region, person);
    }

    public void check(String info) {
        boolean bool = nonterminal.Interpret(info);
        if (bool) {
            System.out.println("识别成功");
        } else {
            System.out.println("识别失败");
        }
    }
}

interface Expression {
    public boolean Interpret(String info);
}

class NonterminalExprssion implements Expression {
    private TerminalExpression region;
    private TerminalExpression person;

    public NonterminalExprssion(TerminalExpression region, TerminalExpression person) {
        this.region = region;
        this.person = person;
    }

    @Override
    public boolean Interpret(String info) {
        String[] str = info.split("的");
        // B区的调试人员 --> str = {"B区", "调试人员"}

        return region.Interpret(str[0]) && person.Interpret(str[1]);
    }
}

class TerminalExpression implements Expression {
    private Set<String> set = new HashSet<>();

    public TerminalExpression(String[] data) {
        // for (遍历对象类型 对象名 : 遍历对象)
        for (String str : data) {
            set.add(str);
        }
    }

    @Override
    public boolean Interpret(String info) {
        return set.contains(info);
    }
}

🎭 优缺点
【优点】
🧡 1、灵活性:解释器模式可以灵活地定义和解释语言表达式,可以根据需要扩展和改变语言的语法和解释规则。
🧡 2、可扩展性:通过新增具体的解释器类,可以方便地扩展和增加新的语言表达式。
🧡 3、易于理解和修改:每个表达式都被封装成独立的解释器对象,易于理解和修改,使得代码结构清晰。
🧡 4、可维护性:由于解释器模式将语法规则和解释逻辑分离,可以更容易地对语言进行修改和维护。
【缺点】
💚 1、复杂性:随着语法规则的复杂化,解释器模式的实现可能会变得复杂,涉及多个解释器的组合和嵌套。
💚 2、执行效率低:解释器模式需要逐个解释和执行表达式,因此在执行过程中可能会存在一定的性能损耗,特别是对于复杂的语言表达式。
💚 3、可扩展性受限:如果需要新增一种全新的语言规则,可能需要修改已有的解释器类或者新增一个全新的解释器类,对于大规模的语言扩展可能会比较麻烦。

==========================================================================================

🎨【漫游之剑】迭代器模式(Iterator)

【循序渐进,层层递进,遍历全境,展现全貌。】

🎈 迭代器模式是一种行为型设计模式,它提供了一种访问聚合对象中各个元素的方式,而无需暴露聚合对象的内部表示

迭代器模式的核心思想是将对聚合对象的遍历操作封装在一个迭代器对象中,通过迭代器对象来顺序访问聚合对象中的元素,而不需要直接暴露聚合对象的内部结构。这样可以使得聚合对象的内部结构可以独立于其遍历算法的变化,从而提高代码的灵活性和可扩展性。

结构图如下:

在这里插入图片描述

在这里插入图片描述


🥽 迭代器模式适用于:

  • 访问一个聚合对象的内容而无须暴露它的内部表示。
  • 支持对聚合对象的多种遍历。
  • 为遍历不同的聚合结构提供一个统一的接口。

代码实现:

import java.util.*;

public class IteratorPattern {
    public static void main(String[] args) {
        BookAggregate bookAggregate = new BookAggregate();

        String[] books = {"数据结构", "操作系统", "计算机网络", "计算机组成原理"};
        double[] prices = {10.24, 20.48, 40.96, 81.92};

        for (int i = 0; i < 4; i ++ ) {
            bookAggregate.Add(new Book(books[i], prices[i]));
        }

        Iterator bookIterator = bookAggregate.CreateIterator();
        while (bookIterator.hasNext()) {
            Book book = (Book) bookIterator.next();
            System.out.println(book.getName() + " " + book.getPrice());
        }
    }
}

interface Iterator {
    public boolean hasNext();
    public Object next();
}

class BookIterator implements Iterator {
    private int index;
    private BookAggregate bookAggregate;

    public BookIterator(BookAggregate bookAggregate) {
        this.index = 0;
        this.bookAggregate = bookAggregate;
    }

    @Override
    public boolean hasNext() {
        if (index < bookAggregate.getSize()) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Object next() {
        Object obj = bookAggregate.get(index);
        index ++ ;

        return obj;
    }
}

interface Aggregate {
    public Iterator CreateIterator();
}

class BookAggregate implements Aggregate {
    private List<Book> list = new ArrayList<Book>();

    public void Add(Book book) {
        list.add(book);
    }

    public Book get(int index) {
        return list.get(index);
    }

    public int getSize() {
        return list.size();
    }

    @Override
    public Iterator CreateIterator() {
        return new BookIterator(this);
    }
}


class Book {
    private String name;
    private double price;

    public Book(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }
}

🎭 优缺点
【优点】
🧡 1、分离了聚合对象和遍历行为:迭代器模式将遍历行为封装在迭代器中,使得聚合对象不需要关注具体的遍历实现。
🧡 2、简化了聚合对象接口:聚合对象只需要提供一个方法来创建迭代器对象,而不需要暴露内部的元素集合。
🧡 3、支持多种遍历方式:可以针对同一个聚合对象定义多个不同的迭代器,实现不同的遍历方式。
【缺点】
💚 1、增加了类的数量:引入迭代器对象会增加代码的复杂性,需要定义额外的迭代器类。
💚 2、遍历过程中的修改问题:如果在遍历过程中修改了聚合对象,可能会导致迭代器的行为不确定。

==========================================================================================

🎨【调解之剑】中介者模式(Mediator)

【扬长避短,化敌为友,协同共赢,大智若愚。】

🎈 中介者模式是一种行为设计模式,它通过提供一个中介者对象,来封装一组对象之间的交互方式。中介者模式通过减少对象之间的直接耦合,促进对象间的松耦合关系,使得对象之间的通信更加灵活和可扩展。

中介者模式中,中介者对象充当了对象之间的调解者和协调者的角色,它负责控制和管理对象之间的交互。当一个对象发生改变时,不需要直接与其他对象进行通信,而是通过中介者对象来进行间接的沟通。这样,对象之间的通信变得简单明了,同时也降低了对象之间的耦合度。

结构图如下:

在这里插入图片描述

在这里插入图片描述


🥽 中介者模式适用于:

  • 一组对象以定义良好但是复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解。
  • 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
  • 想定制一个分布在多个类中的行为,而又不想生成太多的子类。

代码实现:

public class MediatorPattern {
    public static void main(String[] args) {
        ConcreteMediator mediator = new ConcreteMediator();

        Colleague1 colleague1 = new Colleague1(mediator);
        Colleague2 colleague2 = new Colleague2(mediator);

        mediator.setColleague1(colleague1);
        mediator.setColleague2(colleague2);

        colleague1.sendMessage("软考加油");

        colleague2.sendMessage("祝大家软考顺利通过!");
    }
}


abstract class Colleague {
    protected Mediator mediator;
}

class Colleague1 extends Colleague {
    public Colleague1(Mediator mediator) {
        this.mediator = mediator;
    }

    public void sendMessage(String message) {
        mediator.sendMessage(message, this);
    }

    public void Notify(String message) {
        System.out.println("同事1收到消息:" + message);
    }
}

class Colleague2 extends Colleague {
    public Colleague2(Mediator mediator) {
        this.mediator = mediator;
    }

    public void sendMessage(String message) {
        mediator.sendMessage(message, this);
    }

    public void Notify(String message) {
        System.out.println("同事2收到消息:" + message);
    }
}

abstract class Mediator {
    public abstract void sendMessage(String message, Colleague colleague);
}

class ConcreteMediator extends Mediator {
    private Colleague1 colleague1;
    private Colleague2 colleague2;

    public void setColleague1(Colleague1 colleague1) {
        this.colleague1 = colleague1;
    }

    public void setColleague2(Colleague2 colleague2) {
        this.colleague2 = colleague2;
    }

    public void sendMessage(String message, Colleague colleague) {
        if (colleague == colleague1) {
            colleague2.Notify(message); // 让同事2收到消息
        } else {
            colleague1.Notify(message); // 让同事1收到消息
        }
    }
}

🎭 优缺点
【优点】
🧡 1、解耦对象间的关系:中介者模式将对象之间的交互逻辑集中在中介者对象中,使得对象之间的通信变得简单,同时减少了对象之间的直接依赖关系,降低了耦合度。
🧡 2、降低了对象的复杂性:通过引入中介者对象,对象只需关注自身的行为,而不需要了解其他对象的细节,简化了对象的实现和维护过程。
🧡 3、可扩展性和灵活性:由于对象之间的交互逻辑被封装在中介者对象中,因此可以较容易地扩展新的对象和交互规则,而不会对已有的对象产生影响。
【缺点】
💚 1、中介者对象的复杂性:中介者对象需要处理大量的对象之间的交互逻辑,可能会导致中介者对象的复杂性增加。
💚 2、单一点故障:由于对象之间的通信都经过中介者对象,如果中介者对象出现问题,可能会影响到整个系统的正常运行。

==========================================================================================

🎨【回溯之剑】备忘录模式(Memento)

【临危不惧,胸有成竹,记忆犹新,历历在目。】

🎈 备忘录模式是一种行为型设计模式,在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。

结构图如下:

在这里插入图片描述

在这里插入图片描述


🥽 备忘录模式适用于:

  • 必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
  • 如果一个用接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。

代码实现:

import java.util.*;

public class MementoPattern {
    public static void main(String[] args) {
        Caretaker caretaker = new Caretaker();
        Originator originator = new Originator();

        originator.setState("1024");
        Memento backup1 = originator.createMemento();
        caretaker.addMemento(backup1);

        originator.setState("2048");
        Memento backup2 = originator.createMemento();
        caretaker.addMemento(backup2);

        originator.setState("4096");
        Memento backup3 = originator.createMemento();
        caretaker.addMemento(backup3);

        System.out.println(originator.getState());

        caretaker.showMemento();

        Memento memento1 = caretaker.getMemento(2);
        originator.setMemento(memento1);

        System.out.println("根据第2次备份还原之后的状态为:" + originator.getState());
    }
}

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 setMemento(Memento memento) {
        state = memento.getState();
    }
}

class Memento { // 备忘录
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }
}

class Caretaker { // 管理者
    private List<Memento> mementoList = new ArrayList<>();

    public void addMemento(Memento memento) {
        mementoList.add(memento);
    }

    public Memento getMemento(int index) {
        // 判断参数是否合法
        if (index >= 1 && index <= mementoList.size()) {
            return mementoList.get(index - 1);
        }

        return null;
    }

    public void showMemento() {
        int cnt = 1;
        // for (遍历对象类型 对象名 : 遍历对象)
        for (Memento memento : mementoList) {
            System.out.println("第" + cnt + "次备份,状态为:" + memento.getState());

            cnt ++ ;
        }
    }
}

🎭 优缺点
【优点】
🧡 1、分离了存储状态和使用状态,使得系统结构更加清晰。
🧡 2、备忘录对象包含了完整的状态信息,所有状态信息都被保存,保证了数据的完整性。
🧡 3、备忘录对象的可见范围仅限于原发器对象本身和备忘录对象,保持了信息的封装性。
【缺点】
💚 1、如果需要保存的状态数据太多,备忘录对象会消耗大量的内存。
💚 2、备忘录对象的创建和恢复可能会影响系统性能,特别是需要保存和恢复大量状态信息时的性能问题。
💚 3、对象的历史记录可能会很大,需要占用大量的存储空间。

==========================================================================================

🎨【注视之剑】观察者模式(Observer)

【耳聪目明,洞察先机,紧贴脉搏,快速响应。】

🎈 观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象当主题对象的状态发生变化时,所有的观察者都能够收到通知并更新自己的状态

结构图如下:
在这里插入图片描述

在这里插入图片描述


🥽 观察者模式适用于:

在这里插入图片描述


代码实现:

import java.util.*;

public class ObserverPattern {
    public static void main(String[] args) {
        Subject subjectA = new ConcreteSubject("目标A");

        Observer observerB = new ConcreteObserver("张三", subjectA);
        Observer observerC = new ConcreteObserver("李四", subjectA);
        Observer observerD = new ConcreteObserver("王五", subjectA);

        subjectA.setState("更新了");

        System.out.println("======================================");

        subjectA.Detach(observerD);

        subjectA.setState("停更了");
    }
}

interface Subject { // 目标
    public void Attach(Observer observer); // 添加观察者
    public void Detach(Observer observer); // 删除观察者
    public void Notify(); // 状态改变后 通知所有观察者

    public void setState(String state); // 设置状态(改变状态)
    public String getState(); // 获取状态
}

class ConcreteSubject implements Subject {
    private String name;
    private String state;

    private List<Observer> observerList;

    public ConcreteSubject(String name) {
        state = "未更新";
        this.name = name;

        observerList = new ArrayList<Observer>();
    }

    public void setState(String state) {
        this.state = state;

        System.out.println(name + "的状态发生变化,变化后的状态为:" + state);
        Notify();
    }

    public String getState() {
        return state;
    }

    public void Attach(Observer observer) {
        observerList.add(observer);
    }

    public void Detach(Observer observer) {
        observerList.remove(observer);
    }

    public void Notify() {
        // for (遍历对象类型 对象名 : 遍历对象)
        for (Observer observer : observerList) {
            observer.update();
        }
    }
}

interface Observer { // 观察者接口
    public void update(); // 收到通知 更新观察者的状态
}

class ConcreteObserver implements Observer {
    private String name;
    private String state;

    private Subject subject;

    public ConcreteObserver(String name, Subject subject) {
        this.name = name;

        this.subject = subject;
        subject.Attach(this);

        state = subject.getState();
    }

    @Override
    public void update() {
        System.out.println(name + "收到通知");
        state = subject.getState(); // 让当前观察者的状态 和 改变了状态之后的目标的状态保持一致

        System.out.println(name + "改变后的状态为:" + state);
    }
}

🎭 优缺点
【优点】
🧡 1、解耦性强:观察者模式将观察者和主题分离开来,使它们之间的耦合度更低,符合面向对象设计的原则。

🧡 2、可扩展性强:观察者模式可以随时添加新的观察者,也可以随时删除某个观察者,不需要修改主题对象的代码。

🧡 3、灵活性高:观察者模式允许主题和观察者之间存在一对多的关系,主题对象可以向多个观察者发送通知,观察者也可以监控多个主题对象的状态。

🧡 4、可复用性强:观察者模式可以让不同的观察者对象复用同一个主题对象,也可以让不同的主题对象复用同一个观察者对象。
【缺点】
💚 1、有时会引起循环依赖:当主题对象和观察者对象之间存在循环依赖时,会导致系统出现问题,应该避免这种情况的发生。
💚 2、通知顺序不确定:观察者模式中观察者之间是相互独立的,因此它们接收到通知的顺序是不确定的,有可能造成业务逻辑上的错误。
💚 3、观察者过多会降低程序的性能:当观察者过多时,每个观察者都需要进行更新,会占用大量的系统资源和时间。应该根据实际情况确定观察者的个数。

==========================================================================================

🎨【转换之剑】状态模式(State)

【阴晴圆缺,随机应变,处变不惊,泰然处之。】

🎈 状态模式是一种行为型设计模式,它允许一个对象在其内部状态改变时通过调用另一个类中的方法改变其行为,使这个对象看起来如同修改了它的类,而不需要对外暴露其内部状态。该模式将对象包装成不同的状态,使其在不同状态下具有不同的行为表现,从而实现了状态的简化和灵活性。

结构图如下:

在这里插入图片描述

在这里插入图片描述


🥽 状态模式适用于:

在这里插入图片描述


代码实现:

public class StatePattern {
    public static void main(String[] args) {
        Context context = new Context(); // count:3

        System.out.println(context.getState());

        context.Request(); // 购买一个饮料 count = 2
        context.Request(); // 购买一个饮料 count = 1
        context.Request(); // 购买一个饮料 count = 0

        System.out.println(context.getState());

        context.Request(); // 无货 等待补货 补货成功 count = 5

        System.out.println(context.getState());

        context.Request(); // 购买一个饮料 count = 4
        System.out.println(context.getCount());

    }
}

class Context { // 贩卖机
    private int count;

    private State state;

    public Context() {
        count = 3;
        state = new StateA();
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    public void Request() { // 购买一个饮料
        state.Handle(this);
    }

}

interface State {
    public void Handle(Context context);
}

class StateA implements State { // 有货

    @Override
    public void Handle(Context context) {
        int count = context.getCount();

        if (count >= 1) {
            System.out.println("购买成功!");
            context.setCount(count - 1);

            if (context.getCount() == 0) {
                context.setState(new StateB());
            }
        } else {
            System.out.println("购买失败!");
        }
    }
}

class StateB implements State { // 无货

    @Override
    public void Handle(Context context) {
        int count = context.getCount();

        if (count == 0) {
            System.out.println("购买失败!等待补货");

            context.setCount(5);
            System.out.println("补货成功,请重新购买");
            context.setState(new StateA());
        }
    }
}

🎭 优缺点
【优点】
🧡 1、通过封装状态的变化,简化了复杂条件分支语句,使代码结构更加清晰。
🧡 2、可以使对象在不同状态下拥有不同的行为表现,具有良好的扩展性和灵活性。
🧡 3、可以很好地解耦状态之间的相互影响,增加了程序的可维护性。
【缺点】
💚 1、在状态变化较多或状态比较复杂时,可能会有大量的状态实现类,导致类的数量增加和代码复杂度提高。
💚 2、由于状态模式会将对象状态封装在对象内部,因此在状态变化时可能会导致对象的内部状态发生变化,从而影响对象的其他行为。

==========================================================================================

🎨【取舍之剑】策略模式(Strategy)

【目光远大,有备无患,因势利导,适者生存。】

🎈 策略模式是一种行为型设计模式,定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。此模式使得算法可以独立于使用它们的客户而变化。

结构图如下:

在这里插入图片描述

在这里插入图片描述


🥽 策略模式适用于:

在这里插入图片描述


代码实现:

public class StrategyPattern {
    public static void main(String[] args) {
        Strategy add = new AddStrategy();
        Strategy subtraction = new SubtractionStrategy();
        Strategy multiply = new MultiplyStrategy();

        OperationContext context = new OperationContext(add);
        context.Operation(2022, 528);

        context = new OperationContext(subtraction);
        context.Operation(2022, 528);

        context = new OperationContext(multiply);
        context.Operation(2022, 528);
    }
}

class OperationContext {
    private Strategy strategy;

    public OperationContext(Strategy strategy) {
        this.strategy = strategy;
    }

    public void Operation(int a, int b) {
        strategy.TwoNumberOperation(a, b);
    }
}

interface Strategy {
    public void TwoNumberOperation(int a, int b);
}

class AddStrategy implements Strategy {

    @Override
    public void TwoNumberOperation(int a, int b) {
        System.out.println(a + b);
    }
}

class SubtractionStrategy implements Strategy {

    @Override
    public void TwoNumberOperation(int a, int b) {
        System.out.println(a - b);
    }
}

class MultiplyStrategy implements Strategy {

    @Override
    public void TwoNumberOperation(int a, int b) {
        System.out.println(a * b);
    }
}


🎭 优缺点
【优点】
🧡 1、策略模式实现了算法和行为的解耦,使得修改某种算法或行为时对其他不相关的算法和行为没有影响。
🧡 2、策略模式使得可以在运行时动态地切换算法或行为,提高了程序的灵活性和可扩展性。
🧡 3、策略模式可以避免大量的if-else语句,让代码更加简洁和易于维护。
【缺点】
💚 1、如果策略类过多,会导致系统变得复杂,降低可读性。
💚 2、客户端需要了解不同的策略类,才能选择合适的策略实现相应功能,增加了客户端的复杂度。
💚 3、策略模式需要对算法和行为进行抽象,设计者需要根据具体的问题来设计和实现相应的策略类,增加了开发成本。

==========================================================================================

🎨【规范之剑】模板方法模式(Template Method)

【规范有序,一脉相承,奠定基石,步步为营。】

🎈 模板方法模式是一种行为设计模式,其定义一个操作中的算法骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。

结构图如下:
在这里插入图片描述

在这里插入图片描述


🥽 模板方法模式适用于:

在这里插入图片描述


代码实现:

public class TemplateMethodPattern {
    public static void main(String[] args) {
        // 父类名 对象名 = new 子类名();

        Person student = new Student();
        Person teacher = new Teacher();

        student.TemplateMethod();

        System.out.println("=====我是分割线=====");

        teacher.TemplateMethod();
    }
}

abstract class Person {
    public void TemplateMethod() {
        System.out.println("上课 去教室"); // 1
        PrimitiveOperation1(); // 2
        System.out.println("下课 离开教室"); // 3
        PrimitiveOperation2(); // 4
    }

    public abstract void PrimitiveOperation1(); // 原语操作 1 :上课过程 学生 听课…… 老师 讲课
    public abstract void PrimitiveOperation2(); // 原语操作 2 :作业     学生 写作业 提交作业…… 老师 批改作业 打分数
}

class Student extends Person {

    @Override
    public void PrimitiveOperation1() {
        System.out.println("学生:听课 学习 做笔记 提出问题");
    }

    @Override
    public void PrimitiveOperation2() {
        System.out.println("学生:写作业 提交作业");
    }
}

class Teacher extends Person {

    @Override
    public void PrimitiveOperation1() {
        System.out.println("老师:上课 讲课 解答问题 布置作业");
    }

    @Override
    public void PrimitiveOperation2() {
        System.out.println("老师:批改作业 打分数");
    }
}

🎭 优缺点
【优点】
🧡 1、通过将算法的公共部分提取到父类中,避免了代码重复,提高了代码的重用性。
🧡 2、提高子类扩展性。由于子类只需要实现自己所需的特定方法即可,在保证算法结构的同时也可以满足个性化的需求。
🧡 3、通过父类对具体流程的控制,能够更加严格地限制子类方法的调用顺序和内容,从而提高代码的安全性。
【缺点】
💚 1、模板方法模式在扩展某些细节方面存在一定限制,如果想要修改骨架的整体结构,需要修改父类,容易导致代码的破坏性和不稳定性。
💚 2、子类执行过程必须遵循父类中规定的流程,这可能会导致一些性能上的损失,因为不适合某些特定用例。
💚 3、可能会增加系统复杂度,因为通过继承来解决问题需要理解继承机制和抽象类等概念,需要额外的学习成本和开发时间。

==========================================================================================

🎨【访问之剑】访问者模式(Visitor)

【行云流水,寻访天下,解开谜团,洞察真相。】

🎈 访问者模式是一种行为设计模式,表示一个作用于某对象结构中的各元素的操作,使得在不改变各元素的类的前提下定义作用于这些元素的新操作。

结构图如下:

在这里插入图片描述

  • 抽象访问者(Visitor): 声明一个或多个访问操作,同时该操作的参数类型标识了具体被访问的元素。
  • 具体访问者(ConcreteVisitor): 实现抽象访问者声明的操作。
  • 抽象元素(Element): 声明一个 accept 方法,该方法的参数接收一个访问者对象。
  • 具体元素(ConcreteElement): 实现抽象元素定义的接口,元素接受访问的时候通过调用自身的 accept 方法向访问者提供访问接口。
  • 对象结构(ObjectStructure): 容纳元素对象的容器,可能使用不同的方法来遍历元素,例如列表、数组、树等。

🥽 访问者模式适用于:

在这里插入图片描述


代码实现:

import java.util.*;

public class VisitorPattern {
    public static void main(String[] args) {
        PersonStructure structure = new PersonStructure();

        Visitor1 visitor1 = new Visitor1();
        System.out.println("访问者1的访问记录:");
        structure.Accept(visitor1);
        System.out.println("学生年龄的总和:" + visitor1.getStudentAgeSum() + " 老师年龄的总和:" + visitor1.getTeacherAgeSum());

        System.out.println("=========================================");

        Visitor2 visitor2 = new Visitor2();
        System.out.println("访问者2的访问记录:");
        structure.Accept(visitor2);
        System.out.println("学生的最高成绩:" + visitor2.getMaxScore() + " 老师的最高工龄:" + visitor2.getMaxWorkYear());
    }
}

interface Visitor {
    public void visitStudent(Student student); // 访问学生
    public void visitTeacher(Teacher teacher); // 访问老师
}

class Visitor1 implements Visitor { // 访问者1 分别统计学生和老师的年龄总和
    private int studentAgeSum = 0;
    private int teacherAgeSum = 0;

    public int getStudentAgeSum() {
        return studentAgeSum;
    }

    public int getTeacherAgeSum() {
        return teacherAgeSum;
    }

    @Override
    public void visitStudent(Student student) {
        System.out.println("访问者1访问学生:" + student.getName() + " 年龄:" + student.getAge());
        studentAgeSum += student.getAge();
    }

    @Override
    public void visitTeacher(Teacher teacher) {
        System.out.println("访问者1访问老师:" + teacher.getName() + " 年龄:" + teacher.getAge());
        teacherAgeSum += teacher.getAge();
    }
}

class Visitor2 implements Visitor { // 访问者2 分别求出 学生的最高成绩 以及 老师的最高工龄
    private int maxScore = -1;
    private int maxWorkYear = -1;

    public int getMaxScore() {
        return maxScore;
    }

    public int getMaxWorkYear() {
        return maxWorkYear;
    }

    @Override
    public void visitStudent(Student student) {
        System.out.println("访问者2访问学生:" + student.getName() + " 成绩:" + student.getScore());
        maxScore = Math.max(maxScore, student.getScore());
    }

    @Override
    public void visitTeacher(Teacher teacher) {
        System.out.println("访问者2访问老师:" + teacher.getName() + " 工龄:" + teacher.getWorkYear());
        maxWorkYear = Math.max(maxWorkYear, teacher.getWorkYear());
    }
}

class PersonStructure {
    private List<Person> personList = new ArrayList<Person>();

    public PersonStructure() {
        personList.add(new Student("张三", 20, 70));
        personList.add(new Student("李四", 21, 80));
        personList.add(new Student("王五", 22, 90));

        personList.add(new Teacher("李老师", 26, 3));
        personList.add(new Teacher("陈老师", 27, 4));
        personList.add(new Teacher("刘老师", 28, 5));
    }

    public void Accept(Visitor visitor) {
        // for (遍历对象类型 对象名 : 遍历对象)
        for (Person person : personList) {
            person.Accept(visitor);
        }
    }
}

abstract class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public abstract void Accept(Visitor visitor);
}

class Student extends Person {
    private int score;

    public Student(String name, int age, int score) {
        super(name, age);

        this.score = score;
    }

    public int getScore() {
        return score;
    }

    @Override
    public void Accept(Visitor visitor) {
        visitor.visitStudent(this);
    }
}

class Teacher extends Person {
    private int workYear;

    public Teacher(String name, int age, int workYear) {
        super(name, age);

        this.workYear = workYear;
    }

    public int getWorkYear() {
        return workYear;
    }

    @Override
    public void Accept(Visitor visitor) {
        visitor.visitTeacher(this);
    }
}

🎭 优缺点
【优点】
🧡 1、增加新的操作很容易:当需要增加新的操作时,我们只需要增加一个新的访问者类即可,无需修改现有的代码。
🧡 2、将相关行为集中到一起:访问者模式使得同一类对象的所有关注点都被放在了一个类里面,而不是分散在一个个方法中。
🧡 3、简化了对象结构。访问者模式可以将对象结构中遍布各处的类代码移动到同一个访问者中,使得对象结构更加清晰简单。
【缺点】
💚 1、增加新的元素很困难:需要在每一个访问者类中添加新的方法,这样会导致类的数量增加,系统更加庞大。
💚 2、破坏封装性:访问者模式要求访问者对象访问并调用源对象的私有方法,而这些私有方法或属性可能本应该隐藏起来,破坏了对象的封装性。
💚 3、难以理解:访问者模式的代码比较抽象,对于初学者来说理解起来可能比较困难。

==========================================================================================

🎉🎉!! 完结撒花!!🎉🎉

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值