软件设计师--设计模式

1  设计模式分类

ac6c49e7e3c84cdd912115b5ddc114c2.png

2  创建型设计模式

每一个设计模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又 一次地使用该方案而不必做重复劳动。设计模式的核心在于提供了相关问题的解决方案,使得人们可以更加简单方 便的复用成功的设计和体系结构
 
设计模式的四个基本要素:
  • 模式名称
  • 问题:应该在何时使用模式
  • 解决方案:设计的内容
  • 效果:模式应用的效果
设计模式的类别:
  • 创建型模式:主要处理创建对象
  • 结构型模式:主要处理类和对象的组合
  • 行为型模式:主要是描述类或者对象的交互行为

2.1  Factory Method(工厂方法模式)

意图:

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
 

结构:

将工厂抽象为一个接口,定义方法

由子类工厂去具体实现,就可以生成不同的工厂,但方法一样

1680368017f2442a89ededeebab034af.png

6d6e28b42e2e4fa68e6bb3a0cf8490d3.png

 适用性:

45fba3ea7ccd40b883a2e287acf84265.png

代码:

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");
    }
}

2.2   Abstract Factory(抽象工厂模式 )

意图:

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
 

结构:

8bbaf2a82cf9495bb5d83d3dcac147ad.png

 7a9e7386ca284731b95d5bcc66919a3b.png

适用性:

ba1289fbc42a4ba391e75ce5a5dcd86c.png

 代码:

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");
    }
}

2.3  Builder(生成器模式)

意图:

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

结构:

ddee25e9903f43b88fc438201e192c66.png

 697c0cb4a2374e5ca414ce79e0e77cb6.png

 适用性:

5986a7d3f2854eb891af58654b547ef6.png

 代码:

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");
    }
}

2.4  Prototype(原型模式)

意图:

用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

结构:

913415bfd79049d39222f0b1f2101e66.png

适用性:

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

 代码:

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;
    }
}

2.5   Singleton(单例模式)

意图:

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

结构:

0b675bcd8a48481193c16ca7523bb05f.png

适用性:

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

代码: 

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;
    }
}

2.6  总结  

意图

工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。

抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

生成器模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

原型模式:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

ef423552a18347beaaa9063873ce8c6a.png

3  结构型设计模式

3.1  Adapter(适配器)

意图:

将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
 

结构:

07ea35d9d4d8445bb505b5aaa9f1389a.png

b9a45287c6b54f1882fa2c382e863cff.png

适用性:

  • 想使用一个已经存在的类,而它的接口不符合要求。
  • 创建一个可以服用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类) 协同工作。
  • (仅适用于对象Adapter)想使用一个已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接 口。对象适配器可以适配它的父类接口。

选项描述 :

  • 将一个对象加以包装以给客户提供其希望的另外一个接口
  • 想使用一个已经存在的类,而其接口不符合要求
  • 使所有接口不兼容类可以一起工作
  • 将一个类的接口转换成客户希望的另一个接口

代码:

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数据线");
    }
}

3.2  Bridge(桥接)

意图:

将抽象部分与其实现部分分离,使它们都可以独立地变化。

结构:

8a911e4183474f5eb54614a214909932.png

b931d594dd26410782e5ea868594e1a5.png

适用性:

  • 不希望在抽象和它的实 现部分之间有一个固定的绑定关系。例如,这种情况可能是B为,在程序运行时 刻实现部分应可以被选择或者切换。
  • 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这是 Bridge模式传得开发者可以对 不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。
  • 对一个抽象的实现部分的修改应对客户不产生影响,即客户代码不必重新编译。
  • (C++)想对客户完全隐藏抽象的实现部分。
  • 有许多类要生成的类层次结构。
  • 想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。

选项描述:

  • 类的抽象和其实现之间不希望有一个固定的绑定关系
  • 不希望在抽象和它的实现部分之间有一个固定的绑定关系
  • 都给另一个对象提供了一定程度上的间接性,都涉及从自身以外的一个接口向这个对象转发请求。(这是桥接和适配器共同的特征)

代码:

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 { //具体产品A,实现接口Product

    @Override //重写抽象类的方法
    public void Operation() {
        //调用已经设置好的颜色,通过OperationImp方法上色
        //通过父类的this.getName()将产品名称传给Color,Color根据产品名称对应上颜色
        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 + ":蓝色");
    }
}

3.3  Composite(组合)

意图:

将对象组合成树型结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用 具有一致性。

结构:

01786e6f2a0149b380410ebf6c13f642.png

 6ed7ee1df78143a38597fd7cbab4ce7b.png

适用性:

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

代码:

import java.util.*;

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

        AbstractFile folderA = new Folder("folderA"); //实例化文件夹A
        AbstractFile folderB = new Folder("folderB"); //实例化文件夹B

        AbstractFile fileC = new File("fileC"); //实例化文件C
        AbstractFile fileD = new File("fileD"); //实例化文件D
        AbstractFile fileE = new File("fileE"); //实例化文件E

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

        //文件夹对象,从父类继承add方法
        folderA.Add(fileD); //将文件D添加到文件夹A中
        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;
    }
}

3.4  Decorator(装饰器)

意图:

动态地给一个对象添加一些额外的职责。就增加功能而言,Decorator模式比生成子类更加灵活。

结构:

bdc16697f8034f2d869e5b4d78d8d303.png

 

43d6f8debd6a46cbba79057ebbff79fd.png

选项描述:

  • 将一个对象加以包装以提供一些额外的行为
  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
  • 动态地给一个对象添加一些额外的职责

适用性:

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 处理那些可以撤销的职责。
  • 当不能采用生成子类的方式进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生 大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是,由于类定义被隐藏,或类定义不能用于生成 子类。

代码:

public class DecoratorPattern {
    public static void main(String[] args) {
        Person zhangsan = new Student("张三"); //给Person类实例化一个学生
        zhangsan = new DecoratorA(zhangsan); //添加了新职责的张三赋值给新的张三
        zhangsan = new DecoratorB(zhangsan);
        zhangsan.Operation();

        System.out.println("\n=====我是分割线=====");
        
        //父类名 对象名 = new 子类名();
 
        // 对象链
        Person lisi = new DecoratorB(new DecoratorA(new Student("李四")));
    }
}

abstract class Decorator extends Person { //继承了Person又包含一个Person的对象属性
    protected Person person;
}

class DecoratorA extends Decorator { //重写父类装饰器的operation()方法
    public DecoratorA(Person 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; //当前类的name 继承 父类定义的name,并赋值
    }

    @Override
    public void Operation() { //重写父类装饰器的operation()方法
        System.out.print(name + "的职责:学习 ");
    }
}

3.5  Facade(外观)

意图:

为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

结构:

ff2b81d34b9a41a2b36a6d243aee70d1.png

97c8dad4ce334e1dae67d957c3cb96f2.png

选项描述:

  • 将一系列对象加以包装以简化其接口
  • 需要为一个复杂子系统提供一个简单接口

适用性:

  • 要为一个复杂子系统提供一个简单接口时,子系统往往因为不断演化而变得越来越复杂。大多数模式使用 时都会产生更多更小的类,这使得子系统更具有可重用性,也更容易对子系统进行定制,但也给那些不需要定 制子系统的用户带来一些使用上的困难。Facade可以提供一个简单的默认视图,这一视图对大多数用户来说 已经足够,而那些需要更多的可定制性的用户可以越过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("执行子系统三的功能");
    }
}

3.6  Flyweight(享元)

意图:

运用共亨技术有效地支持大量细粒度的对象。

结构:

e910092da54146f384e9d44debaa14f9.png

选项描述:

  • 因使用大量的对象而造成很大的存储开销时,进行对象共享,以减少对象数量从而达到较少的内存占用并提升性能。

适用性:

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

代码:

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 { //图形的工厂
    //<String, Shape>键值对  对应 <颜色,形状>
    private Map<String, Shape> map = new HashMap<String, Shape>(); 

    public Shape getShape(String key) { //获取图形,key为颜色
        if (!map.containsKey(key)) { //如果key值不存在
            map.put(key, new Circle(key)); //put 添加
            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);
    }
}

3.7  Proxy(代理)

意图:

为其他对象提供一种代理以控制对这个对象的访问。
 

选项描述:

  • 将一个对象加以包装以控制对这个对象的访问
  • 在需要比较通用和复杂的对象指针代替简单的指针时
  • 为其他对象提供一种代理以控制对这个对象的访问

结构:

83c478364b9f4bc5ae02b7ce143f7b8d.png

适用性:

Proxy模式适用于在需要比较通用和复杂的对象指针代替简单的指针的时候,常见情况有:
  • 远程代理(Remote Proxy)为一个对象在不同地址空间提供局部代表。
  • 虚代理(Virtual Proxy)根据需要创建开销很大的对象。
  • 保护代理(Protection Proxy)控制对原始对象的访问,用于对象应该有不同的访问权限的时候。
  • 智能引用(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。典型用途包 括:对指向实际对象的引用计数,这样当该对象没有引用时,可以被自动释放;当第一次引用一个持久对 象时,将它装入内存;在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。

代码:

public class ProxyPattern {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject(); //创建一个真正的主体
        Proxy proxy = new Proxy(realSubject); // 实例化代理对象,将realSubject传进去
        //指定对象进行代购

        proxy.buy(); //调用realSubject对象的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("付钱");
    }
}

3.8  结构型设计模式总结  

1f3691451fab4928a3ca16a9268bdc79.png

4  行为型设计模式

4.1  Chain of Responsibility(责任链)

意图:

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求`,直到有一个对象处理它为止。

结构:

f852c6b6909243dd8da555c03e43cf2b.png

选项描述:

  • 有多个对象可以处理一个请求,在运行时刻自动确定由哪个对象处理
  • 一个客户需要使用一组相关对象
  • 想在不明确指定接收者的情况下向多个对象中的一个提交一个请求

适用性:

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

代码:

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("无法审批");
            }
        }
    }
}

4.2  Command(命令)

意图:

将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

结构:

1a44e1ea60264da7bc62905dc4e8bfdd.png

选项描述:

  • 抽象出执行的动作以参数化某对象
  • 将请求封装为对象从而可以使用不同的请求对客户进行参数化
  • 在不同的时刻指定、排列和执行请求

适用性:

  • 抽象出待执行的动作以参数化某对象(。Command模式是过程语言中的回调(Callback机制的一个面向对 象的替代品。
  • 在不同的时刻指定、排列和执行请求一个Command对象可以有一个与初始请求无关的生存期。如果一个请 求的接收者可用一种与地址空间无关的方式表达,那么就可以将负责该请求的命令对象传递给另一个不同的 进程并在那儿实现该请求。
  • 支持取消操作Command的Execute操作可在实施操作前将状态存储起来,在取消探作时这个状态用来消除 该操作的影响。Command接口必须添加一个Unexecute操作,该操作取消上一次Execute 调用的效果。执行 的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用Unexecute和Execute来实现重 数不限的“取消和“重做”。
  • 支持修改日志这样当系统崩溃时,这些修改可以被重做一遍。在 Command 接口中添加装载操作和存储操 作,可以用来保持变动的一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令 并用Execute操作重新执行它们。
  • 用构建在原语操作上的高层操作构造一个系统)这样一种结构在支持事务(Transaction)的信息系统中很 常见。Command模式提供了对事务进行建模的方法。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("电视机关机了...");
    }
}

4.3  Interpreter(解释器)

意图:

 

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

结构:

ab105950c9eb4bfb94b809891e6420ff.png

选项描述:

  • 有一个语言需要解释执行,并且可将句子表示为一个抽象语法树

适用性:

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);
    }
}

4.4  Iterator(迭代器)

意图:

提供一种方法顺序访问一个聚合对象中的各个元素,且不需要暴露该对象的内部表示。

结构:

83ebc56c83d947da9fcb13a616742360.png

选项描述:

  • 访问一个聚合对象的内容而无须暴露它的内部表示

适用性:

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

代码:

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;
    }
}

4.5  Mediator(中介者)

意图:

用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

结构:

17d04343bde843ad822e03496bd25314.png

选项描述:

  • 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象
  • 一组对象以定义良好但是复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解。
  • 减少多个对象或类之间的通信复杂性
  • 中介模式和观察者模式是相互竞争的模式,主要差别是:前者的中介对象封装了其他对象间的通信,而后者通过引入其他对象来分布通信。
  • 欲使一个后端数据模型能够被多个前端用户界面连接

适用性:

  • 一组对象以定义良好但是复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解。

代码:

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收到消息
        }
    }
}

4.6  Memento(备忘录)

意图:

在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。

结构:

832cbbbac52a4fb7941e8d03c16a7cb8.png

选项描述:

  • 将对象的状态恢复到先前的状态
  • 在不破坏封装性的前提下,捕获对象的内部状态并在对象之外保存
  • 必须保存一个对象在某一个时刻的(部分)状态

适用性:

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

代码:

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++;
        }
    }
}

4.7  Observer(观察者)

意图:

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

结构:

dfae1aeedede4ab3acc33d9e6d5ecf5b.png

选项描述:
  • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁时
  • 在发布-订阅(Publish-Subscribe)消息模型中,订阅者订阅一个主题后,当该主题有新消息到达时,所有订阅者都会收到通知
  • 使所要交互的对象尽量松耦合
  • 当一个对象状态改变时所有依赖它的对象得到通知并自动更新
  • 一个对象的改变需要改变其它对象

适用性:

  • 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在独立的对象中以使它们可以各自独立地改变和复用。
  • 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变时。
  • 当一个对象必须通知其他对象,而它又不能假定其他对象是谁,即不希望这些对象是紧耦合的。

代码:

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);
    }
}

4.8  State(状态)

意图:

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

结构:

cb4bc5c748e94c72ba4e2aa66150cb91.png

选项描述:

  • 一个对象的行为决定于其状态且必须在运行时刻根据状态改变行为
  • 一个对象在其内部状态改变时改变其行为

适用性:

  • 一个对象的行为决定于它的状态,并且它必须在运行时刻根据状态改变它的行为。
  • 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态常用一个或多个枚 举常量表示。通常,有多个操作包含这一相同的条件结构。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());
        }
    }
}

4.9  Strategy(策略)

意图:

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

结构:

b0b80c50897e4efab149ec7e76f3125a.png

选项描述:

  • 需要使用一个算法地不同变体
  • 许多相关的类仅仅是行为有异
  • 在设计某购物中心的收银软件系统时,要求能够支持在不同时期推出打折、返利、满减等不同促销活动

适用性:

  • 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置-个类的方法。
  • 需要使用一个算法的不同变体。例如,定义一些反映不同空间的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时,可以使厨策略模式。
  • 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
  • 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,将相关的条件分支移入它们各自的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);
    }
}

4.10  Template Method(模板方法)

意图:

表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的新操作。

结构:

ff08a5a415634494be3e7a2589670d6b.png

选项描述:

  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作

适用性:

  • 一个对象结构包含很多类对象,它们有不同的接口,而用户想对这些对象实施一些依赖于其具体类的操作。
  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而又想要避免这些操作“污染”这些对象的类。Visitor 使得用户可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
  • 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。

代码:

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("老师:批改作业 打分数");
    }
}

4.11  Visitor(访问者)

意图:

定义一个操作中的算法骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

结构:

2fe4d88a9afd430899fc5a6a3d4fa1c1.png

适用性:

  • 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
  • 各子类中公共的行为应被提取出来并集中到一个公共父类中,以避免代码重复。
  • 控制子类扩展。模板方法旨在特定点调用“hook”操作(默认的行为,子类可以在必要时进行重定义扩展),这就只允许在这些点进行扩展。

代码:

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);
    }
}

4.12  行为型设计模式总结

0a7a40a78bce4b86b2f0865518808f6a.png

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值