23种设计模式模式笔记+易懂案例

Java设计模式

前言

这其实算我个人学习的一个笔记,我这里的标题只有22种,俗称的23种是因为工厂模式一般分为两种,工厂模式与抽象工厂。

一、设计模式是什么?

1.设计模式的定义

设计模式的一般定义如下:设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过 分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性

2.设计模式的分类

类型模式名称
创建型模式单例模式
创建型模式简单工厂模式
创建型模式工厂方法模式
创建型模式抽象工厂模式
创建型模式原型模式
创建型模式建造者模式
结构型适配器模式
结构型桥接模式
结构型组合模式
结构型装饰模式
结构型外观模式
结构型享元模式
结构型代理模式
行为型责任链模式
行为型命令模式
行为型解释器模式
行为型迭代器模式
行为型中介者模式
行为型备忘录模式
行为型观察者模式
行为型状态模式
行为型策略模式
行为型模板方法模式
行为型访问者模式

二、设计模式的实现

1.工厂模式

(1)工厂三兄弟之简单工厂模式
package com.example.demo.pattern.creational;

/**
 * 功能描述: 简单工厂模式
 *
 * @author luxiaomeng
 * @date 2020/8/18   9:28
 * 修改日志: 暂无
 */
public class SimpleFactoryPattern {
    public static void main(String[] args) {
        BaseProduct a = Factory.getProduct("A");
        System.out.println(a.productName());
        BaseProduct b = Factory.getProduct("B");
        System.out.println(b.productName());
    }
}

/**
 * 我是水
 */
abstract class BaseProduct {
    public abstract String productName();
}

/**
 * 我是橙汁
 */
class ProductA extends BaseProduct {
    @Override
    public String productName() {
        return "I am A";
    }
}

/**
 * 我是可乐
 */
class ProductB extends BaseProduct {
    @Override
    public String productName() {
        return "I am B";
    }
}

/**
 * 我是工厂
 */
class Factory {
    public static BaseProduct getProduct(String name){
        if ("A".equals(name)) {
            return new ProductA();
        }
        if ("B".equals(name)) {
            return new ProductB();
        }
        return new BaseProduct() {
            @Override
            public String productName() {
                return "I am Base";
            }
        };
    }
}

由代码看出想要任何产品都得修改SimpleFactoryPattern类中main方法的代码,这里可以做一些优化。

创建config.xml

<?xml version="1.0" encoding="utf-8" ?>
<config>
    <productType>A</productType>
</config>
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.*;
import java.io.File;

/**
 * 功能描述: 简单工厂模式-优化
 *
 * @author luxiaomeng
 * @date 2020/8/18   9:28
 * 修改日志: 暂无
 */
public class SimpleFactoryPattern {
    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = dbf.newDocumentBuilder();
        Document doc = builder.parse(new File("E:\\WorkSpace\\IDEA\\study\\src\\main\\java\\com\\example\\demo\\pattern\\creational\\plus\\config.xml"));
        NodeList nodeList = doc.getElementsByTagName("productType");
        Node classNode = nodeList.item(0).getFirstChild();
        String name = classNode.getNodeValue().trim();
        BaseProduct factory = Factory.getProduct(name);
        System.out.println( factory.productName());
    }
}

/**
 * 我是水
 */
abstract class BaseProduct {
    public abstract String productName();
}

/**
 * 我是雪碧
 */
class ProductA extends BaseProduct {
    @Override
    public String productName() {
        return "I am A";
    }
}

/**
 * 我是可乐
 */
class ProductB extends BaseProduct {
    @Override
    public String productName() {
        return "I am B";
    }
}

/**
 * 我是工厂
 */
class Factory {
    public static BaseProduct getProduct(String name){
        if ("A".equals(name)) {
            return new ProductA();
        }
        if ("B".equals(name)) {
            return new ProductB();
        }
        return new BaseProduct() {
            @Override
            public String productName() {
                return "I am Base";
            }
        };
    }
}
(2)工厂三兄弟之工厂方法模式

刚才通过建造了一个工厂,通过用水来生产可乐与雪碧。随着企业的扩大,推出的产品越来越多,一个工厂生产更多不同的产品时,该工厂需要不断地调整。所以我们根据不同的产品推出了不同的工厂来专门生产某一个产品。

package com.example.demo.pattern.creational.factory.factorymethod;

/**
 * 功能描述: 简单工厂模式
 *
 * @author luxiaomeng
 * @date 2020/8/18   9:28
 * 修改日志: 暂无
 */
public class FactoryMethodPattern {
    public static void main(String[] args) {
        BaseProduct product = new ProductA();
        System.out.println(  product.productName());
    }
}

/**
 *  产品规范-产品都得有名称
 */
interface  BaseProduct {
     String productName();
}

/**
 * 我是橙汁
 */
class ProductA implements BaseProduct {
    @Override
    public String productName() {
        return "I am 橙汁";
    }
}

/**
 * 我是可乐
 */
class ProductB implements BaseProduct {
    @Override
    public String productName() {
        return "I am 可乐";
    }
}

/**
 * 工厂规范
 */
interface BaseFactory {
    BaseProduct createProduct();
}

/**
 * 橙汁工厂
 */
class FactoryA implements BaseFactory{
    @Override
    public BaseProduct createProduct() {
        return new ProductA();
    }
}
/**
 * 可乐工厂
 */
class FactoryB implements BaseFactory{
    @Override
    public BaseProduct createProduct() {
        return new ProductB();
    }
}

同样利用反射优化

config.xml

<?xml version="1.0" encoding="utf-8" ?>
<config>
    <productName>com.example.demo.pattern.creational.factory.factorymethod.plus.FactoryA</productName>
</config>
package com.example.demo.pattern.creational.factory.factorymethod.plus;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;

/**
 * 功能描述: 简单工厂模式
 *
 * @author luxiaomeng
 * @date 2020/8/18   9:28
 * 修改日志: 暂无
 */
public class FactoryMethodPattern {
    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = dbf.newDocumentBuilder();
        Document doc = builder.parse(new File("E:\\WorkSpace\\IDEA\\study\\src\\main\\java\\com\\example\\demo\\pattern\\creational\\factory\\factorymethod\\plus\\config.xml"));
        NodeList nodeList = doc.getElementsByTagName("productName");
        Node classNode = nodeList.item(0).getFirstChild();
        String productName = classNode.getNodeValue().trim();
        Class<?> productFactory = Class.forName(productName);
        BaseFactory o = (BaseFactory) productFactory.newInstance();
        System.out.println(o.createProduct().productName());
    }
}

/**
 * 产品规范-产品都得有名称
 */
interface BaseProduct {
    String productName();
}

/**
 * 我是橙汁
 */
class ProductA implements BaseProduct {
    @Override
    public String productName() {
        return "I am 橙汁";
    }
}

/**
 * 我是可乐
 */
class ProductB implements BaseProduct {
    @Override
    public String productName() {
        return "I am 可乐";
    }
}

/**
 * 工厂规范
 */
interface BaseFactory {
    BaseProduct createProduct();


}
/**
 * 橙汁工厂
 */
class FactoryA implements BaseFactory {
    @Override
    public BaseProduct createProduct() {
        return new ProductA();
    }
}
/**
 * 可乐工厂
 */
class FactoryB implements BaseFactory {
    @Override
    public BaseProduct createProduct() {
        return new ProductB();
    }
}

(3)工厂三兄弟之抽象工厂模式
package com.example.demo.pattern.creational.factory.abstractfactorypattern;

/**
 * 功能描述: 工厂方法模式
 *  由于橙汁、可乐产品的火热,我们针对这两件产品分别建厂,利润大大增加。
 *  为了继续占领市场,我们又推出了无糖可乐,根据市场调查无糖可乐的市场需求并不大,
 *  单独建厂不太适合,但是为了满足小众需求,我们将该产品合并到可乐工厂
 * @author luxiaomeng
 * @date 2020/8/18   9:28
 * 修改日志: 暂无
 */
public class AbstractFactoryPattern {
    public static void main(String[] args) {
        BaseProduct product = new ProductC();
        System.out.println(  product.productName());
    }
}

/**
 *  产品规范-产品都得有名称
 */
interface  BaseProduct {
     String productName();
}

/**
 * 我是橙汁
 */
class ProductA implements BaseProduct {
    @Override
    public String productName() {
        return "I am 橙汁";
    }
}

/**
 * 我是可乐
 */
class ProductB implements BaseProduct {
    @Override
    public String productName() {
        return "I am 可乐";
    }
}/**
 * 我是无糖可乐
 */
class ProductC implements BaseProduct {
    @Override
    public String productName() {
        return "I am 无糖可乐";
    }
}

/**
 * 工厂规范
 */
interface BaseFactory {
    BaseProduct createProduct(String args);
}

/**
 * 橙汁工厂
 */
class FactoryA implements BaseFactory{
    @Override
    public BaseProduct createProduct(String args) {
        return new ProductA();
    }
}
/**
 * 可乐工厂
 */
class FactoryB implements BaseFactory{
    @Override
    public BaseProduct createProduct(String args) {
        if ("无糖".equals(args)) {
            return new ProductC();
        }
        return new ProductB();
    }
}

2.单例模式

​ 单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。

单例模式有 3 个特点:

  1. 单例类只有一个实例对象;
  2. 该单例对象必须由单例类自行创建;
  3. 单例类对外提供一个访问该单例的全局访问点;
(1)懒汉式单例
public class LazySingleton
{
    //volatile:中文意为易变的,是java的一个关键字,volatile具有可见性、有序性,不具备原子性。
    //可见性:使用volatile修饰的变量会强制将修改的值立即写入主存,主存中值的更新会使缓存中的值失效
    private static volatile LazySingleton instance=null;    //保证 instance 在所有线程中同步
    private LazySingleton(){}    //private 避免类在外部被实例化
    public static synchronized LazySingleton getInstance()
    {
        //getInstance 方法前加同步
        if(instance==null)
        {
            instance=new LazySingleton();
        }
        return instance;
    }

(2)饿汉式单例
public class HungrySingleton
{
    private static final HungrySingleton instance=new HungrySingleton();
    private HungrySingleton(){}
    public static HungrySingleton getInstance()
    {
        return instance;
    }
}
(3)IoDH

​ 饿汉式单例类不能实现延迟加载,不管将来用不用始终占据内存;懒汉式单例类线程安全控 制烦琐,而且性能受影响。可见,无论是饿汉式单例还是懒汉式单例都存在这样那样的问 题,有没有一种方法,能够将两种单例的缺点都克服,而将两者的优点合二为一呢?答案 是:Yes!下面我们来学习这种更好的被称之为Initialization Demand Holder (IoDH)的技术。

/**
 * 功能描述: IoDH单例
 * 利用内部类的延时加载
 *
 * @author luxiaomeng
 * @date 2020/8/18   15:26
 * 修改日志: 暂无
 */
public class IoDHSingleton {
    private IoDHSingleton() {
    }

    private static class HolderClass {
        private final static IoDHSingleton instance = new IoDHSingleton();
    }

    public static IoDHSingleton getInstance() {
        return HolderClass.instance;
    }

    public static void main(String args[]) {
        IoDHSingleton s1, s2;
        s1 = IoDHSingleton.getInstance();
        s2 = IoDHSingleton.getInstance();
        System.out.println(s1 == s2);
    }
}

3.原型模式

原型设计模式:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。

应用场景:

  • 对象之间相同或相似,即只是个别的几个属性不同的时候。
  • 对象的创建过程比较麻烦,但复制比较简单的时候。
(1)浅拷贝

模式的结构

原型模式包含以下主要角色。

  1. 抽象原型类:规定了具体原型对象必须实现的接口。
  2. 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
  3. 访问类:使用具体原型类中的 clone() 方法来复制新的对象。

原型类实现clone()方法,在clone方法中调用父类的clone()方法即可实现,但是只能拷贝基本数据类型

package com.example.demo.pattern.creational.prototype;

/**
 * 功能描述: 原型模式-浅拷贝
 *
 * @author luxiaomeng
 * @date 2020/8/18   15:46
 * 修改日志: 暂无
 */
public class SunWuKong implements Cloneable{

    private String name = "孙悟空";
    private JinGuBang jinGuBang;

    public String getName() {
        return name;
    }

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

    public JinGuBang getJinGuBang() {
        return jinGuBang;
    }

    public void setJinGuBang(JinGuBang jinGuBang) {
        this.jinGuBang = jinGuBang;
    }

    public SunWuKong() {
        //1.从石头里蹦出来
        //2.取金箍棒
        //3.大闹天宫
        //。。。。。。。
        //总之,再创建一个孙悟空时太麻烦了。不如直接复制一个
    }

    /**
     * 于是孙悟空采用72变:实现java.lang包下的Cloneable接口,但实际实现调用的是Object.clone方法
     */
    @Override
    public Object clone() throws CloneNotSupportedException {

        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        SunWuKong sunWuKong = new SunWuKong();
        JinGuBang jinGuBang = new JinGuBang();
        sunWuKong.setJinGuBang(jinGuBang);
        SunWuKong sixEar = (SunWuKong) sunWuKong.clone();
        System.out.println(sunWuKong==sixEar);  //false
        System.out.println(sunWuKong.jinGuBang==sixEar.jinGuBang);  // true 可以看出孙悟空的金箍棒没有复制过来
    }
}
/**
 * 孙悟空的金箍棒
 */
class JinGuBang {
    private String name="金箍棒";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
(2)深拷贝

利用序列化来实现深拷贝,拿走猴哥的金箍棒

步骤:1)原型与引用类型实现Serializable序列化接口

​ 2)利用ObjectOutputStreamObjectInputStream读取对象

package com.example.demo.pattern.creational.prototype.plus;


import java.io.*;

/**
 * 功能描述: 原型模式-浅拷贝
 *
 * @author luxiaomeng
 * @date 2020/8/18   15:46
 * 修改日志: 暂无
 */
public class SunWuKong implements Serializable {

    private String name = "孙悟空";
    private JinGuBang jinGuBang;

    public String getName() {
        return name;
    }

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

    public JinGuBang getJinGuBang() {
        return jinGuBang;
    }

    public void setJinGuBang(JinGuBang jinGuBang) {
        this.jinGuBang = jinGuBang;
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        SunWuKong sunWuKong = new SunWuKong();
        JinGuBang jinGuBang= new JinGuBang();
        sunWuKong.setJinGuBang(jinGuBang);
        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bao);
        oos.writeObject(sunWuKong);
        ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        SunWuKong liuer =(SunWuKong) ois.readObject();
        System.out.println(sunWuKong == liuer);
        System.out.println(sunWuKong.jinGuBang == liuer.jinGuBang);
    }
}

/**
 * 孙悟空的金箍棒
 */
class JinGuBang implements Serializable {
    private String name = "金箍棒";

    public String getName() {
        return name;
    }

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

4.建造者模式

建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可 以创建不同的表示。建造者模式是一种对象创建型模式。
建造者模式一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就 可以构建它们,用户不需要知道内部的具体构建细节

在建造者模式结构图中包含如下几个角色:
● Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接 口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一 类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。
●ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方 法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
●Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品 的内部表示并定义它的装配过程。
●Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽 象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装 配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建 造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。

/**
 * 功能描述: 建造者模式
 * 假定要开发一个网站,该公司有两套方案,
 * 一、前端采用vue 后端采用java
 * 二、前端asp,后端.net
 *
 * @author luxiaomeng
 * @date 2020/8/18   16:35
 * 修改日志: 暂无
 */
public class Builder {
    public static void main(String[] args) {
        // 客户决定采用java开发
        JavaDever javaDever = new JavaDever();
        XiangMuZhuGuan xiangMuZhuGuan = new XiangMuZhuGuan();
        WebSite webSite = xiangMuZhuGuan.dev(javaDever);
        System.out.println(webSite.getFront()+"-"+webSite.getEnd());
        // 前端采用vue开发完成-后端采用Java开发完成
    }
}

class WebSite {
    // 前端开发
    private String front;
    // 后端开发
    private String end;

    public String getFront() {
        return front;
    }

    public void setFront(String front) {
        this.front = front;
    }

    public String getEnd() {
        return end;
    }

    public void setEnd(String end) {
        this.end = end;
    }
}

/**
 * 架构师
 */
abstract class JiaGouShi {
    WebSite webSite = new WebSite();

    public abstract void buildFront();
    public abstract void buildEnd();

    public WebSite kaiFaWebSite() {
        return webSite;
    }
}

/**
 * Java开发人员
 */
class JavaDever extends JiaGouShi{
    @Override
    public void buildFront() {
        webSite.setFront("前端采用vue开发完成");
    }

    @Override
    public void buildEnd() {
        webSite.setEnd("后端采用Java开发完成");
    }
}

/**
 * .net开发人员
 */
class NetDever extends JiaGouShi {
    @Override
    public void buildFront() {
        webSite.setFront("前端采用asp开发完成");
    }

    @Override
    public void buildEnd() {
        webSite.setEnd("后端采用net开发完成");
    }
}

/**
 * 项目主管
 */
class XiangMuZhuGuan{
    public WebSite dev(JiaGouShi jiaGouShi) {
        jiaGouShi.buildFront();
        jiaGouShi.buildEnd();
        return jiaGouShi.kaiFaWebSite();
    }
}

5.适配器模式

适配器模式概述

​ 与电源适配器相似,在适配器模式中引入了一个被称为适配器(Adapter)的包装类,而它所包装 的对象称为适配者(Adaptee),即被适配的类。适配器的实现就是把客户类的请求转化为对适 配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调 用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。因此, 适配器让那些由于接口不兼容而不能交互的类可以一起工作。
​ 适配器模式可以将一个类的接口和另一个类的接口匹配起来,而无须修改原来的适配者接口 和抽象目标类接口。适配器模式定义如下:
​ 适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。

(1)对象适配器模式
package com.example.demo.pattern.structural.adapter;

/**
 * 功能描述: 对象适配器模式
 *
 * @author luxiaomeng
 * @date 2020/8/19   13:42
 * 修改日志: 暂无
 */
public class AdapterPattern {

    public static void main(String[] args) {
    LaptopPowerInterface laptopPower = new LaptopPowerAdapter();
        Integer power = laptopPower.getPower();
        System.out.println("笔记本电脑此时接口的电压为:"+power+"v");
        //笔记本电脑此时接口的电压为:20
    }
}

/**
 * 适配者
 */
class HomePower{
    private Integer power = 220;

    public Integer getPower() {
        return power;
    }
}

/**
 * 抽象目标:笔记本电源接口
 */
interface LaptopPowerInterface {
    public Integer getPower();
}
/*
 *适配器:电源适配器
 */
class LaptopPowerAdapter implements LaptopPowerInterface{
    private HomePower homePower;

    public LaptopPowerAdapter() {
        this.homePower = new HomePower();
    }

    /**
     * 削减电压为20V
     */
    @Override
    public Integer getPower() {
       return this.homePower.getPower()-200;
    }
}

(2)类适配器模式
package com.example.demo.pattern.structural.adapter.classasapter;

/**
 * 功能描述: 类适配器模式
 *
 * @author luxiaomeng
 * @date 2020/8/19   13:42
 * 修改日志: 暂无
 */
public class AdapterPattern {

    public static void main(String[] args) {
    LaptopPowerInterface laptopPower = new LaptopPowerAdapter();
        Integer power = laptopPower.getPower();
        System.out.println("笔记本电脑此时接口的电压为:"+power+"v");
        //笔记本电脑此时接口的电压为:20
    }
}

/**
 * 适配者
 */
class HomePower{
     Integer power = 220;
}

/**
 * 抽象目标:笔记本电源接口
 */
interface LaptopPowerInterface {
    public Integer getPower();
}
/*
 *适配器
 */
class LaptopPowerAdapter extends HomePower implements LaptopPowerInterface{

    /**
     * 削减电压为20V
     */
    @Override
    public Integer getPower() {
       return super.power-200;
    }
}

(3)双向适配器模式
package com.example.demo.pattern.structural.adapter.twoway;

/**
 * 功能描述: 双向适配器模式
 * 例子:充当协调者
 *
 * @author luxiaomeng
 * @date 2020/8/19   13:42
 * 修改日志: 暂无
 */
class Adapter implements Target, Adaptee {                        //同时维持对抽象目标类和适配者的引用						private	Target	target;						private	Adaptee	adaptee;
    private Target target;
    private Adaptee adaptee;

    public Adapter(Target target) {
        this.target = target;
    }

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
        adaptee.specificRequest();
    }

    @Override
    public void specificRequest() {
        target.request();
    }
}

interface Target {
    public void request();
}

interface Adaptee {
    public void specificRequest();
}

(4)缺省适配器模式
package com.example.demo.pattern.structural.adapter.defaultadapter;

/**
 * 功能描述: 缺省适配器模式
 *
 * @author luxiaomeng
 * @date 2020/8/19   13:42
 * 修改日志: 暂无
 */
public class AdapterPattern {

    public static void main(String[] args) {
        PhonePower phonePower = new ChongDianBao();
        phonePower.typeC();  //我提供了typec手机的接口
        phonePower.mac(); // null

    }
}

/**
 * 抽象目标  - 充电接口规范
 */
interface PhonePower {
    public void typeC();

    public void mac();
}

/*
 * 抽象类
 */
abstract class PowerAdapter implements PhonePower {
    @Override
    public void typeC() {

    }

    @Override
    public void mac() {

    }
}

/**
 * 充电宝
 */
class ChongDianBao extends PowerAdapter {

    @Override
    public void typeC() {
        System.out.println("我提供了typec手机的接口");
    }

}

6.桥接模式

​ 桥接模式是一种很实用的结构型设计模式,如果软件系统中某个类存在两个独立变化的维 度,通过该模式可以将这两个维度分离出来,使两者可以独立扩展,让系统更加符合“单一职 责原则”。与多层继承方案不同,它将两个独立变化的维度设计为两个独立的继承等级结构, 并且在抽象层建立一个抽象关联,该关联关系类似一条连接两个独立继承结构的桥,故名桥 接模式。
​ 桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联取代了传统的多层继承, 将类之间的静态继承关系转换为动态的对象组合关系,使得系统更加灵活,并易于扩展,同 时有效控制了系统中类的个数。桥接定义如下:
​ 桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是 一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
桥接模式的结构与其名称一样,存在一条连接两个继承等级结构的桥,

桥接模式主要包含如下几个角色:

​ Abstraction:抽象类。
​ RefinedAbstraction:扩充抽象类。
​ Implementor:实现类接口。
​ ConcreteImplementor:具体实现类 。

package com.example.demo.pattern.structural.bridge;

/**
 * 功能描述: 比如一个网游,有武当、少林门派的角色,角色又可以选择阵营(好,坏)
 *
 * @author luxiaomeng
 * @date 2020/8/20   9:40
 * 修改日志: 暂无
 */
public class BridgePattern {

    public static void main(String[] args) {
        //创建一个角色
        Role role = new WuDang();
        role.setMenPai(); //设置门派
        System.out.println(role.menPai);
        role.setZhenYing(new JiangHu());
        role.zhenYing.setZhenYing();
        /**
         * 您选择了武当派
         * 加入了江湖阵营
         */
    }
}

abstract class Role {
    // 门派
    public String menPai;

    public ZhenYing zhenYing;

    public void setZhenYing(ZhenYing zhenYing) {
        this.zhenYing = zhenYing;
    }

    public abstract void setMenPai();
}


class WuDang extends Role {
    @Override
    public void setMenPai() {
        this.menPai = "您选择了武当派";
    }
}

class ShaoLing extends Role {
    @Override
    public void setMenPai() {
        this.menPai = "您选择了少林";
    }
}

/**
 * 阵营接口
 */
interface ZhenYing {
    public void setZhenYing();
}

/**
 * 江湖
 */
class JiangHu implements ZhenYing {
    @Override
    public void setZhenYing() {
        System.out.println("加入了江湖阵营");
    }
}

/**
 *
 */
class ChaoTing implements ZhenYing {
    @Override
    public void setZhenYing() {
        System.out.println("加入了朝廷阵营");
    }
}

7.组合模式

组合模式概述
对于树形结构,当容器对象(如文件夹)的某一个方法被调用时,将遍历整个树形结构,寻 找也包含这个方法的成员对象(可以是容器对象,也可以是叶子对象)并调用执行,牵一而 动百,其中使用了递归调用的机制来对整个结构进行处理。由于容器对象和叶子对象在功能 上的区别,在使用这些对象的代码中必须有区别地对待容器对象和叶子对象,而实际上大多 数情况下我们希望一致地处理它们,因为对于这些对象的区别对待将会使得程序非常复杂。 组合模式为解决此类问题而诞生,它可以让叶子对象和容器对象的使用具有一致性。
组合模式定义如下:
组合模式(Composite Pattern):组合多个对象形成树形结构以表示具有“整体—部分”关系的层 次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致 性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。

在组合模式结构图中包含如下几个角色:
● Component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象声明接口, 在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。

● Leaf(叶子构件):它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在 抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过异常等方式进行处 理。
● Composite(容器构件):它在组合结构中表示容器节点对象,容器节点包含子节点,其子 节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象 构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子 节点的业务方法。

package com.example.demo.pattern.structural.composite;

import java.util.ArrayList;

/**
 * 功能描述: 组合模式
 * 举例:给不同文件类型的文件杀毒
 *
 * @author luxiaomeng
 * @date 2020/8/20   10:27
 * 修改日志: 暂无
 */
public class CompositePattern {

    public static void main(String[] args) {
        AbstractFile file1, file2, file3, file4, folder1, folder2, folder3;
        folder1 = new Folder("Sunny的资料");
        folder2 = new Folder("图像文件");
        folder3 = new Folder("文本文件");
        file1 = new ImageFile("小龙女.jpg");
        file2 = new ImageFile("张无忌.gif");
        file3 = new TextFile("九阴真经.txt");
        file4 = new TextFile("葵花宝典.doc");
        folder2.add(file1);
        folder2.add(file2);
        folder3.add(file3);
        folder3.add(file4);
        folder1.add(folder2);
        folder1.add(folder3);
        folder1.killVirus();
    }
}

//抽象文件类:抽象构件
abstract class AbstractFile {
    public abstract void add(AbstractFile file);

    public abstract void remove(AbstractFile file);

    public abstract AbstractFile getChild(int i);

    public abstract void killVirus();
}

//图像文件类:叶子构件
class ImageFile extends AbstractFile {
    private String name;

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

    @Override
    public void add(AbstractFile file) {
        System.out.println("对不起,不支持该方法!");
    }

    @Override
    public void remove(AbstractFile file) {
        System.out.println("对不起,不支持该方法!");
    }

    @Override
    public AbstractFile getChild(int i) {
        System.out.println("对不起,不支持该方法!");
        return null;
    }

    @Override
    public void killVirus() {
        //模拟杀毒
        System.out.println("----对图像文件'" + name + "'进行杀毒");
    }
}

//文本文件类:叶子构件
class TextFile extends AbstractFile {
    private String name;

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

    @Override
    public void add(AbstractFile file) {
        System.out.println("对不起,不支持该方法!");
    }

    @Override
    public void remove(AbstractFile file) {
        System.out.println("对不起,不支持该方法!");
    }

    @Override
    public AbstractFile getChild(int i) {
        System.out.println("对不起,不支持该方法!");
        return null;
    }

    @Override
    public void killVirus() {
        //模拟杀毒
        System.out.println("----对文本文件'" + name + "'进行杀毒");
    }
}

//文件夹类:容器构件
class Folder extends AbstractFile {
    //定义集合fileList,用于存储AbstractFile类型的成员						、    public Folder(String name) {
    private ArrayList<AbstractFile> fileList = new ArrayList<AbstractFile>();
    private String name;

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

    @Override
    public void add(AbstractFile file) {
        fileList.add(file);
    }

    @Override
    public void remove(AbstractFile file) {
        fileList.remove(file);
    }

    @Override
    public AbstractFile getChild(int i) {
        return (AbstractFile) fileList.get(i);
    }

    @Override
    public void killVirus() {
        System.out.println("****对文件夹'" + name + "'进行杀毒");
        for (Object obj : fileList) {
            ((AbstractFile) obj).killVirus();
        }
    }
}

8.装饰者模式

装饰模式概述
装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为,在现实生活 中,这种情况也到处存在,例如一张照片,我们可以不改变照片本身,给它增加一个相框, 使得它具有防潮的功能,而且用户可以根据需要给它增加不同类型的相框,甚至可以在一个 小相框的外面再套一个大相框。
装饰模式是一种用于替代继承的技术,它通过一种无须定义子类的方式来给对象动态增加职 责,使用对象之间的关联关系取代类之间的继承关系。在装饰模式中引入了装饰类,在装饰 类中既可以调用待装饰的原有类的方法,还可以增加新的方法,以扩充原有类的功能。

装饰模式定义如下:
装饰模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,就增加对象功能来说, 装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。

在装饰模式结构图中包含如下几个角色:
● Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实 现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对 象,实现客户端的透明操作。
● ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实 现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
● Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体 职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前 构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
● ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每 一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增 加新的方法用以扩充对象的行为。

package com.example.demo.pattern.structural.decorator;

/**
 * 功能描述: 装饰模式
 * 例子:魅族17ota屏幕刷新率
 *
 * @author luxiaomeng
 * @date 2020/8/21   10:05
 * 修改日志: 暂无
 */
public class DecoratorPattern {
    public static void main(String[] args) {
        Meizu17 meizu17 = new Meizu17();
        OtaDecorator ota = new OtaDecorator(meizu17);
        ota.screenreFreshRate();
        // 90HZ屏幕选项
        //120hz屏幕选项
    }
}

/**
 * 抽象类构建
 */
abstract class Phone{
    public abstract  void screenreFreshRate();
}

/**
 * 具体构件类
 */
class Meizu17 extends Phone {
    @Override
    public void screenreFreshRate() {
        System.out.println("90HZ屏幕选项");
    }
}

/**
 * 构件装饰类
 */
class OtaDecorator extends Phone {
    private Phone phone;

    public OtaDecorator(Phone phone) {
        this.phone = phone;
    }


    @Override
    public void screenreFreshRate() {
        phone.screenreFreshRate();
        System.out.println("120hz屏幕选项");
    }
}

9.外观模式

外观模式定义如下: 外观模式:为子系统中的一组接口提供一个统一的入口。外观模式定义 了一个高层接口,这个接口使得这一子系统更加容易使用。

外观模式包含如下两个角色:

(1) Facade(外观角色):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个 或者多个)子系统的功能和责任;在正常情况下,它将所有从客户端发来的请求委派到相应 的子系统去,传递给相应的子系统对象处理。
(2) SubSystem(子系统角色):在软件系统中可以有一个或者多个子系统角色,每一个子系统 可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被 客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求;子系统并不知道外 观的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。

package com.example.demo.pattern.structural.facade;

/**
 * 功能描述: 外观模式(该类就是个外观角色)
 * 角色:外观角色,子系统角色
 * 例子: 蜜雪冰城门面中,一个销售(外观角色),一个准备材料,一个制作
 * @author luxiaomeng
 * @date 2020/8/24   16:19
 * 修改日志: 暂无
 */
public class FacadePattern {
    A a = new A();
    B b = new B();

    void sale() {
        a.prepare();
        b.make();
        System.out.println("拿给买家");
    }

    public static void main(String[] args) {
        FacadePattern fp = new FacadePattern();
        fp.sale();
        //我在准备材料
        //我在制作
        //拿给买家
    }

}

interface Sale {
    void saleDrink();
}

class A {
    void prepare() {
        System.out.println("我在准备材料");
    }
}
class B {
    void make () {
        System.out.println("我在制作");
    }
}

10.享元模式

​ 当一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等 问题。例如在一个文本字符串中存在很多重复的字符,如果每一个字符都用一个单独的对象 来表示,将会占用较多的内存空间,那么我们如何去避免系统中出现大量相同或相似的对 象,同时又不影响客户端程序通过面向对象的方式对这些对象进行操作?享元模式正为解决 这一类问题而诞生。享元模式通过共享技术实现相同或相似对象的重用,在逻辑上每一个出 现的字符都有一个对象与之对应,然而在物理上它们却共享同一个享元对象,这个对象可以 出现在一个字符串的不同地方,相同的字符对象都指向同一个实例,在享元模式中,存储这 些共享实例对象的地方称为享元池(Flyweight Pool)。我们可以针对每一个不同的字符创建一个 享元对象,将其放在享元池中,需要时再从享元池取出。

享元模式定义如下:
享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使
用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于 享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种 对象结构型模式。

package com.example.demo.pattern.structural.flyweight;

import java.util.Hashtable;

/**
 * 功能描述: 享元模式
 * 例子: 围棋盘上,黑白棋子的复用
 *
 * @author luxiaomeng
 * @date 2020/8/24   16:46
 * 修改日志: 暂无
 */
public class FlyWeightPattern {
    public static void main(String[] args) {
        IgoChessman black1, black2, black3, white1, white2;
        IgoChessmanFactory factory;
        //获取享元工厂对象
        factory = IgoChessmanFactory.getInstance();
        //通过享元工厂获取三颗黑子
        black1 = IgoChessmanFactory.getIgoChessman("b");
        black2 = IgoChessmanFactory.getIgoChessman("b");
        black3 = IgoChessmanFactory.getIgoChessman("b");
        System.out.println("判断两颗黑子是否相同:" + (black1 == black2));
        //通过享元工厂获取两颗白子
        white1 = IgoChessmanFactory.getIgoChessman("w");
        white2 = IgoChessmanFactory.getIgoChessman("w");
        System.out.println("判断两颗白子是否相同:" + (white1 == white2));        //显示棋子,同时设置棋子的坐标位置
        black1.display(new Coordinates(1, 2));
        black2.display(new Coordinates(3, 4));
        black3.display(new Coordinates(1, 3));
        white1.display(new Coordinates(2, 5));
        white2.display(new Coordinates(2, 4));
    }
}

//坐标类:外部状态类
class Coordinates {
    private int x;
    private int y;

    public Coordinates(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return this.x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return this.y;
    }

    public void setY(int y) {
        this.y = y;
    }
}

class IgoChessmanFactory {
    private static IgoChessmanFactory instance = new IgoChessmanFactory();
    private static Hashtable ht;    //使用Hashtable来存储享元对象,充当享元池

    private IgoChessmanFactory() {
        ht = new Hashtable();
        IgoChessman black, white;
        black = new BlackIgoChessman();
        ht.put("b", black);
        white = new WhiteIgoChessman();
        ht.put("w", white);
    }

    //返回享元工厂类的唯一实例
    public static IgoChessmanFactory getInstance() {
        return instance;
    }

    //通过key来获取存储在Hashtable中的享元对象
    public static IgoChessman getIgoChessman(String color) {
        return (IgoChessman) ht.get(color);
    }
}

//围棋棋子类:抽象享元类
abstract class IgoChessman {
    public abstract String getColor();

    public	void	display(Coordinates	coord){
        System.out.println("棋子颜色:" + this.getColor() + ",棋子位置:" + coord.getX() + "," + coord.getY());			}
}

//黑色棋子类:具体享元类
class BlackIgoChessman extends IgoChessman {
    @Override
    public String getColor() {
        return "黑色";
    }
}

//白色棋子类:具体享元类
class WhiteIgoChessman extends IgoChessman {
    @Override
    public String getColor() {
        return "白色";
    }
}

11.代理模式

代理模式:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。代理模式是一种对象结构型模式。在代理模式中引入了一个新的代理对象,代理对象在客户 端对象和目标对象之间起到中介的作用,它去掉客户不能看到的内容和服务或者增添客户需 要的额外的新服务。

(1) Subject(抽象主题角色):它声明了真实主题和代理主题的共同接口,这样一来在任何使 用真实主题的地方都可以使用代理主题,客户端通常需要针对抽象主题角色进行编程。
(2) Proxy(代理主题角色):它包含了对真实主题的引用,从而可以在任何时候操作真实主题 对象;在代理主题角色中提供一个与真实主题角色相同的接口,以便在任何时候都可以替代 真实主题;代理主题角色还可以控制对真实主题的使用,负责在需要的时候创建和删除真实 主题对象,并对真实主题对象的使用加以约束。通常,在代理主题角色中,客户端在调用所 引用的真实主题操作之前或之后还需要执行其他操作,而不仅仅是单纯调用真实主题对象中 的操作。
(3) RealSubject(真实主题角色):它定义了代理角色所代表的真实对象,在真实主题角色中 实现了真实的业务操作,客户端可以通过代理主题角色间接调用真实主题角色中定义的操 作

(1)静态代理
package com.example.demo.pattern.structural.proxy.staticproxy;

/**
 * 功能描述: 用中介租房流程实现静态代理
 * 中介租房流程: 找房源(中介)-签合同-收取中介费(中介)
 *  角色: 顾客-》被代理类
 *         中介-》代理类
 *         接口
 * @author luxiaomeng
 * @date 2020/8/13   16:05
 * 修改日志: 暂无
 */
public class RentingHouseDemo {

    public static void main(String[] args) {
        // 张三想租房子
        Customer customer = new Customer("张三");
        // 中介大姐
        Agent agent = new Agent(customer);
        agent.signContract();
        /**输出结果:
         * 中介:正在找房子
         * 张三租到了房子
         * 中介:给我钱
         */
    }
}

/**
 * 租房业务
 */
interface RentingHouse {
    //签订租房合同
    void signContract();
}

/**
 * 客户
 */
class Customer implements RentingHouse {
    private String name;

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

    @Override
    public void signContract() {
        System.out.println(this.name + "租到了房子");
    }
}

/**
 * 中介
 */
class Agent implements RentingHouse {

    Customer customer;

    //找我就给他办事
    public Agent(Customer customer) {
        this.customer = customer;
    }

    //我们中介是这样干租房业务的
    @Override
    public void signContract() {
        findHouse();
        this.customer.signContract();
        giveMeMoney();
    }

    public void findHouse() {
        System.out.println("中介:正在找房子");
    }

    public void giveMeMoney() {
        System.out.println("中介:收取中介费");
    }
}


(2)动态代理
1️⃣ jdk实现动态代理
package com.example.demo.pattern.structural.proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 功能描述: 以租房案例实现jdk的动态代理
 * 中介租房流程: 找房源(中介)-签合同-收取中介费(中介)
 *  角色: 顾客-》被代理类
 *         中介-》代理类
 *         接口
 * @author luxiaomeng
 * @date 2020/8/13   16:45
 * 修改日志: 暂无
 */
public class DynamicProxy {
    public static void main(String[] args) {
        // 张三想租房子
        Customer customer = new Customer("张三");
        Handler handler = new Handler(customer);
        RentingHouse o = (RentingHouse)Proxy.newProxyInstance(customer.getClass().getClassLoader(), customer.getClass().getInterfaces(), handler);
        o.signContract();
    }
}

/**
 * 租房业务
 */
interface RentingHouse {
    //签订租房合同
    void signContract();
}

/**
 * 客户1123132
 */
class Customer implements RentingHouse {
    private String name;

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

    @Override
    public void signContract() {
        System.out.println(this.name + "租到了房子");
    }
}

/**
 * 调用处理器
 */
class Handler implements InvocationHandler{

    Object object;

    //找我就给他办事
    public Handler(Object object) {
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        findHouse();
        Object returnValue = method.invoke(object, args);

        giveMeMoney();
        return returnValue;
    }
    public void findHouse() {
        System.out.println("中介:正在找房子");
    }

    public void giveMeMoney() {
        System.out.println("中介:收取中介费");
    }
}



2️⃣ CGLIB实现动态代理
package com.example.demo.pattern.structural.proxy.dynamic.cglib;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 功能描述: 以租房案例实现jdk的动态代理
 * 中介租房流程: 找房源(中介)-签合同-收取中介费(中介)
 *  角色: 顾客-》被代理类
 *         中介-》代理类
 *         接口
 * @author luxiaomeng
 * @date 2020/8/14   14:46
 * 修改日志: 暂无
 */
public class DynamicProxy {

    public static void main(String[] args) {
        // 通过CGLIB动态代理获取代理对象的过程
        Enhancer enhancer = new Enhancer();
        // 设置enhancer对象的父类
        enhancer.setSuperclass(Customer.class);
        // 设置enhancer的回调对象
        enhancer.setCallback(new Handler());
        // 创建代理对象
        Customer proxy= (Customer)enhancer.create();
        proxy.signContract();
    }


}

/**
 * 客户
 */
class Customer {
    private String name;


    public void signContract() {
        System.out.println( "租到了房子");
    }
}

/**
 * 调用处理器
 */
class Handler implements MethodInterceptor {

    public void findHouse() {
        System.out.println("中介:正在找房子");
    }

    public void giveMeMoney() {
        System.out.println("中介:收取中介费");
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        findHouse();
        Object invoke = methodProxy.invokeSuper(o, objects);
        giveMeMoney();
        return invoke;
    }
}

12.责任链模式

职责链模式定义如下:职责链模式(Chain of Responsibility Pattern):避免请求发送者与接收者 耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传 递请求,直到有对象处理它为止。职责链模式是一种对象行为型模式。

在职责链模式结构图中包含如下几个角色:
● Handler(抽象处理者):它定义了一个处理请求的接口,一般设计为抽象类,由于不同的 具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者 的下家还是一个处理者,因此在抽象处理者中定义了一个抽象处理者类型的对象(如结构图 中的successor),作为其对下家的引用。通过该引用,处理者可以连成一条链。

● ConcreteHandler(具体处理者):它是抽象处理者的子类,可以处理用户请求,在具体处理 者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前需要进行判断,看是 否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理 者中可以访问链中下一个对象,以便请求的转发。

在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这 个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上 的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织 链和分配责任

package com.example.demo.pattern.behavioral.chain;

/**
 * 功能描述: 责任链模式
 *  例子:富士康工厂生产手机 A负责装配,B负责贴膜,C负责测试 必须按ABC的顺序来
 * @author luxiaomeng
 * @date 2020/8/25   13:52
 * 修改日志: 暂无
 */
public class ChainOfResponsibility {
    public static void main(String[] args) {
        // 创建手机
        Phone phone = new Phone();
        // 创建责任链
        Handler a = new A();
        Handler b = new B();
        Handler c = new C();
        a.setNext(b);
        b.setNext(c);
        a.work(phone);
        //A组装了手机
        //B贴了膜
        //C进行了测试
        //手机制造完成
        
    }
}

class Phone {
    // 状态  1组装 2已贴膜 3已测试
    private int status =0;

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }
}

/**
 * 抽象处理类
 */
abstract class Handler {
    protected Handler next;

    public abstract void work(Phone phone);

    public Handler getNext() {
        return next;
    }

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

class A extends Handler {
    @Override
    public void work(Phone phone) {
        if (phone.getStatus() == 0) {
            System.out.println("A组装了手机");
            phone.setStatus(1);
            next.work(phone);
        }

    }
}
class B extends Handler {
    @Override
    public void work(Phone phone) {
        if (phone.getStatus() == 1) {
            System.out.println("B贴了膜");
            phone.setStatus(2);
            next.work(phone);
        }

    }
}
class C extends Handler {
    @Override
    public void work(Phone phone) {
        if (phone.getStatus() == 2) {
            System.out.println("C进行了测试");
            phone.setStatus(3);
            System.out.println("手机制造完成");
        }

    }
}

13.命令模式

命令模式(CommandPattern):将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。

package com.example.demo.pattern.behavioral.command;

/**
 * 功能描述: 命令模式
 * 案例:简易加法计算器
 *
 * @author luxiaomeng
 * @date 2020/8/26   9:54
 * 修改日志: 暂无
 */
public class CommandPattern {
    public static void main(String[] args) {
        CalculatorForm calculatorForm = new CalculatorForm();
        AbstractCommand command = new ConcreteCommand();
        calculatorForm.setCommand(command);
        calculatorForm.compute(10);
        calculatorForm.undo();
    }
}

// 加法类:请求接收者
class Adder {
    private int num =0;//定义初始值为0

    //加法操作,每次讲传入的值与num作加法运算,并返回结果
    public int add(int value) {
        num += value;
        return num;
    }
}

// 抽象命令类
abstract class AbstractCommand {
    public abstract int execute(int value);//声明命令执行方法
    public abstract int undo();//声明命令撤销方法
}
// 具体命令类
class ConcreteCommand extends AbstractCommand {
    private Adder adder = new Adder();
    private int value;
    // 加法操作
    @Override
    public int execute(int value) {
        this.value = value;
        return adder.add(value);
    }

    // 撤销操作
    @Override
    public int undo() {
        return adder.add(-value);
    }
}

// 计算器界面类:请求发送者
class CalculatorForm {
    private AbstractCommand command;

    public void setCommand(AbstractCommand abstractCommand) {
        this.command = abstractCommand;
    }

    public void compute(int value) {
        int i = command.execute(value);
        System.out.println("执行运算-运算结果为:" + i);
    }

    public void undo() {
        int i = command.undo();
        System.out.println("执行撤销,运算结果为:"+i);
    }
}

14.解释器模式

解释器模式概述
解释器模式是一种使用频率相对较低但学习难度较大的设计模式,它用于描述如何使用面向 对象语言构成一个简单的语言解释器。在某些情况下,为了更好地描述某一些特定类型的问 题,我们可以创建一种新的语言,这种语言拥有自己的表达式和结构,即文法规则,这些问 题的实例将对应为该语言中的句子。此时,可以使用解释器模式来设计这种新的语言。对解 释器模式的学习能够加深我们对面向对象思想的理解,并且掌握编程语言中文法规则的解释 过程。
解释器模式定义如下:解释器模式(Interpreter Pattern):定义一个语言的文法,并且建立一个 解释器来解释该语言中的句子,这里的“语言”是指使用规定格式和语法的代码。解释器模式是一种类行为型模式。

在解释器模式结构图中包含如下几个角色:

● AbstractExpression(抽象表达式):在抽象表达式中声明了抽象的解释操作,它是所有终结 符表达式和非终结符表达式的公共父类。

● TerminalExpression(终结符表达式):终结符表达式是抽象表达式的子类,它实现了与文法 中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例。通常在一个 解释器模式中只有少数几个终结符表达式类,它们的实例可以通过非终结符表达式组成较为 复杂的句子。

● NonterminalExpression(非终结符表达式):非终结符表达式也是抽象表达式的子类,它实 现了文法中非终结符的解释操作,由于在非终结符表达式中可以包含终结符表达式,也可以 继续包含非终结符表达式,因此其解释操作一般通过递归的方式来完成。

● Context(环境类):环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通 常它临时存储了需要解释的语句。

package com.example.demo.pattern.behavioral.interpreter;
import java.util.*;
/**
 * 功能描述: 解释器模式
 * 例子:输入一组表达式,判断上车的乘客是否收费,如果是本地的老人妇女儿童不收费
 *<expression> ::= <city>的<person>
 *   <city> ::=  本地|外地
 *   <person> ::= 老人|妇女|儿童
 * @author luxiaomeng
 * @date 2020/8/26   10:39
 * 修改日志: 暂无
 */
public class InterpreterPattern {
    public static void main(String[] args) {
        Context bus=new Context();
        bus.freeRide("本地的老人");
        bus.freeRide("外地的年轻人");
        bus.freeRide("本地的妇女");
        bus.freeRide("外地的儿童");
        bus.freeRide("本地的儿童");
    }
}
//抽象表达式类
interface Expression
{
    public boolean interpret(String info);
}
//终结符表达式类
class TerminalExpression implements Expression
{
    private Set<String> set= new HashSet<String>();
    public TerminalExpression(String[] data)
    {
        for(int i=0;i<data.length;i++) {
            set.add(data[i]);
        }
    }
    @Override
    public boolean interpret(String info)
    {
        if(set.contains(info))
        {
            return true;
        }
        return false;
    }
}
//非终结符表达式类
class AndExpression implements Expression
{
    private Expression city=null;
    private Expression person=null;
    public AndExpression(Expression city,Expression person)
    {
        this.city=city;
        this.person=person;
    }
    @Override
    public boolean interpret(String info)
    {
        String s[]=info.split("的");
        return city.interpret(s[0])&&person.interpret(s[1]);
    }
}
//环境类
class Context
{
    private String[] citys={"本地"};
    private String[] persons={"老人","妇女","儿童"};
    private Expression cityPerson;
    public Context()
    {
        Expression city=new TerminalExpression(citys);
        Expression person=new TerminalExpression(persons);
        cityPerson=new AndExpression(city,person);
    }
    public void freeRide(String info)
    {
        boolean ok=cityPerson.interpret(info);
        if(ok) {
            System.out.println("您是"+info+",您本次乘车免费!");
        } else {
            System.out.println(info+",您不是免费人员,本次乘车扣费2元!");
        }
    }
}

15.迭代器模式

迭代器模式(Iterator Pattern):提供一种方法来访问聚合对象,而不用暴露这个对象的内部表 示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。

在迭代器模式结构图中包含如下几个角色:

● Iterator(抽象迭代器):它定义了访问和遍历元素的接口,声明了用于遍历数据元素的方法,例如:用于获取第一个元素的first()方法,用于访问下一个元素的next()方法,用于判断是 否还有下一个元素的hasNext()方法,用于获取当前元素的currentItem()方法等,在具体迭代器 中将实现这些方法。

● ConcreteIterator(具体迭代器):它实现了抽象迭代器接口,完成对聚合对象的遍历,同时 在具体迭代器中通过游标来记录在聚合对象中所处的当前位置,在具体实现时,游标通常是 一个表示位置的非负整数。

● Aggregate(抽象聚合类):它用于存储和管理元素对象,声明一个createIterator()方法用于 创建一个迭代器对象,充当抽象迭代器工厂角色

● ConcreteAggregate(具体聚合类):它实现了在抽象聚合类中声明的createIterator()方法,该 方法返回一个与该具体聚合类对应的具体迭代器ConcreteIterator实例。

package com.example.demo.pattern.behavioral;

import java.util.ArrayList;
import java.util.List;

/**
 * 功能描述: 迭代器模式
 * 例子:类似于jdk集合中的迭代器
 *
 * @author luxiaomeng
 * @date 2020/8/27   9:10
 * 修改日志: 暂无
 */
public class IteratorPattern {
    public static void main(String[] args) {
        List products = new ArrayList();
        products.add("奶茶");
        products.add("咖啡");
        products.add("牛奶");
        AbstractObjectList list;
        AbstractIterator iterator;
        list = new ProductList(products);
        iterator = list.createIterator();
        System.out.println("正向遍历");
        while (!iterator.isLast()) {
            System.out.println(iterator.getNextItem());
            iterator.next();
        }
    }
}

// 抽象聚合类
abstract class AbstractObjectList {
    protected List<Object> objects = new ArrayList<>();

    public AbstractObjectList(List objects) {
        this.objects = objects;
    }

    public void addObject(Object object) {
        this.objects.add(object);
    }

    public void removeObject(Object object) {
        this.objects.remove(object);
    }

    public List getObjects() {
        return this.objects;
    }

    //声明创建迭代器对象的抽象工厂方法
    public abstract AbstractIterator createIterator();
}

class ProductList extends AbstractObjectList {
    public ProductList(List objects) {
        super(objects);
    }

    @Override
    public AbstractIterator createIterator() {
        return new ProductIterator(this);
    }

}

// 抽象迭代器
interface AbstractIterator {
    public void next();

    public boolean isLast();

    public void previous();

    public boolean isFirst();

    public Object getNextItem();

    public Object getPreviousItem();
}

//商品迭代器:具体迭代器
class ProductIterator implements AbstractIterator {
    private ProductList productList;
    private List products;
    private int cursor1;    //定义一个游标,用于记录正向遍历的位置
    private int cursor2;    //定义一个游标,用于记录逆向遍历的位置

    public ProductIterator(ProductList list) {
        this.productList = list;
        this.products = list.getObjects();
        cursor1 = 0;
        cursor2 = products.size() - 1;
    }

    @Override
    public void next() {
        if (cursor1 < products.size()) {
            cursor1++;
        }
    }

    @Override
    public boolean isLast() {
        return (cursor1 == products.size());
    }

    @Override
    public void previous() {
        if (cursor2 > -1) {
            cursor2--;
        }
    }

    @Override
    public boolean isFirst() {
        return	(cursor2	==	-1);
    }

    @Override
    public Object getNextItem() {
        return	products.get(cursor1);
    }

    @Override
    public Object getPreviousItem() {
        return	products.get(cursor2);
    }
}

16.中介者模式

中介者模式(Mediator Pattern):用一个中介对象(中介者)来封装一系列的对象交互,中 介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之 间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。

● Mediator(抽象中介者):它定义一个接口,该接口用于与各同事对象之间进行通信。
● ConcreteMediator(具体中介者):它是抽象中介者的子类,通过协调各个同事对象来实现 协作行为,它维持了对各个同事对象的引用。
● Colleague(抽象同事类):它定义各个同事类公有的方法,并声明了一些抽象方法来供子类 实现,同时它维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信。
● ConcreteColleague(具体同事类):它是抽象同事类的子类;每一个同事对象在需要和其他 同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信;在具体同 事类中实现了在抽象同事类中声明的抽象方法

package com.example.demo.pattern.behavioral.mediator;

import java.util.HashMap;
import java.util.Map;

/**
 * 功能描述: 中介者模式
 * 业务场景:  平常写信需要记录对方的地址,我们用了QQ以后,服务器来维护这种关系
 *            模拟发消息  B -A   A -B
 * @author luxiaomeng
 * @date 2020/9/4   11:58
 * 修改日志: 暂无
 */
public class MediatorPattern {
    public static void main(String[] args) {
        A a =new A();
        B b = new B();
        TencentServer tencentServer = new TencentServer();
        tencentServer.setUser(a);
        tencentServer.setUser(b);
        a.sendMessageToServer(tencentServer);
        b.sendMessageToServer(tencentServer);
    }
}

abstract class User {
    String qqId;
    String name;
    public abstract void sendMessageToServer(Server server);
}

interface Server {

    public void sendMessage(String sendUserQQ,String receiveUserQQ);
}

class TencentServer implements Server {
    Map<String ,User> map = new HashMap();
    public void setUser(User user) {
        map.put(user.qqId, user);
        System.out.println(user.name+"上线了");
    }
    @Override
    public void sendMessage(String sendUserQQ,String receiveUserQQ) {
        System.out.println(map.get(sendUserQQ).name+"给"+map.get(receiveUserQQ).name+"发消息");
    }
}

class A extends User {

    public A() {
        this.qqId = "8888";
        this.name = "张三";
    }

    @Override
    public void sendMessageToServer(Server server) {
        server.sendMessage(this.qqId,"9999");
    }
}
class B extends User {
    public B() {
        this.qqId = "9999";
        this.name = "李四";
    }

    @Override
    public void sendMessageToServer(Server server) {
        server.sendMessage(this.qqId,"8888");
    }
}

17.备忘录模式

备忘录模式定义:

备忘录模式(Memento Pattern):在不破坏封装的前提下,捕获一个对象的内部状态,并在 该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是一种对 象行为型模式,其别名为Token。

角色:

●Originator(原发器):它是一个普通类,可以创建一个备忘录,并存储它的当前内部状态,也可以使用备忘录来恢复其内部状态,一般将需要保存内部状态的类设计为原发器。
●Memento(备忘录):存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录 的设计一般可以参考原发器的设计,根据实际需要确定备忘录类中的属性。需要注意的是, 除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用,原发器的设计在不同 的编程语言中实现机制会有所不同。
●Caretaker(负责人):负责人又称为管理者,它负责保存备忘录,但是不能对备忘录的内容 进行操作或检查。在负责人类中可以存储一个或多个备忘录对象,它只负责存储对象,而不 能修改对象,也无须知道对象的实现细节。

package com.example.demo.pattern.behavioral.memento;

import javax.persistence.criteria.CriteriaBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * 功能描述: 备忘录模式
 * 模拟一下编程工具的撤销功能吧
 *
 * @author luxiaomeng
 * @date 2020/9/4   14:42
 * 修改日志: 暂无
 */
public class MementoPattern {
    public static void main(String[] args) {
        // 撤销管理对象
        Caretaker caretaker = new Caretaker();

        InputText inputText = new InputText();
        inputText.setText("public");
        caretaker.add(inputText.save());
        inputText.setText("public void");
        caretaker.add(inputText.save());
        inputText.setText("public void main");
        // 展示当前内容
        System.out.println(inputText.getText());
        // 开始撤销
        inputText.restore(caretaker.get());
        System.out.println(inputText.getText());
        // 再次撤销
        inputText.restore(caretaker.get());
        System.out.println(inputText.getText());
        //public void main
        //public void
        //public
    }

}

class InputText {
    private String text;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public CheXiao save() {
        return new CheXiao(this.text);
    }

    public void restore(CheXiao cheXiao) {
        this.text = cheXiao.getText();
    }
}

/**
 * 撤销键
 */
class CheXiao {

    private String text;

    public CheXiao(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

class Caretaker {
    private Stack<CheXiao> list = new Stack<>();

    public void add(CheXiao cheXiao) {
        list.push(cheXiao);
    }

    public CheXiao get() {
        return list.pop();
    }
}

18.观察者模式

观察者模式定义如下:观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系, 使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式 的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器 (Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。

在观察者模式结构图中包含如下几个角色:
● Subject(目标):目标又称为主题,它是指被观察的对象。在目标中定义了一个观察者集 合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察 者对象,同时它定义了通知方法notify()。目标类可以是接口,也可以是抽象类或具体类。
● ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含有经常发生改变的数 据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义 的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。
● Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接 口声明了更新数据的方法update(),因此又称为抽象观察者。
● ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它 存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观 察者Observer中定义的update()方法。通常在实现时,可以调用具体目标类的attach()方法将自 己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除。

package com.example.demo.pattern.behavioral.observer;

import java.util.ArrayList;

/**
 * 功能描述: 观察者模式
 * 描述:创建金庸群侠战队,某一个成员遭受攻击,别的成员去救援
 *
 * @author luxiaomeng
 * @date 2020/9/7   10:18
 * 修改日志: 暂无
 */
public class ObserverPattern {
    public static void main(String[] args) {
//        定义观察目标对象
        BaseAllyControlCenter acc;
        acc = new ConcreteAllyControlCenter("金庸群侠");
//        定义四个观察者对象
        Observer player1, player2, player3, player4;
        player1 = new Player("杨过");
        acc.join(player1);
        player2 = new Player("令狐冲");
        acc.join(player2);
        player3 = new Player("张无忌");
        acc.join(player3);
        player4 = new Player("段誉");
        acc.join(player4);
//        某成员遭受攻击
        player1.beAttacked(acc);
    }
}

//抽象观察类
interface Observer {
    public String getName();

    public void setName(String name);

    public void help();

    //声明支援盟友方法
    public void beAttacked(BaseAllyControlCenter acc);
    //声明遭受攻击方法
}

//战队成员类:具体观察者类
class Player implements Observer {
    private String name;

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

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

    @Override
    public String getName() {
        return this.name;
    }

    //支援盟友方法的实现
    @Override
    public void help() {
        System.out.println("坚持住," + this.name + "来救你!");
    }

    //遭受攻击方法的实现,当遭受攻击时将调用战队控制中心类的通知方法notifyObserver()来通知
    @Override
    public void beAttacked(BaseAllyControlCenter acc) {
        System.out.println(this.name + "被攻击!");
        acc.notifyObserver(name);
    }
}

//战队控制中心类:目标类
abstract class BaseAllyControlCenter {
    protected String allyName;    //战队名称
    protected ArrayList<Observer> players = new ArrayList<Observer>();

    public void setAllyName(String allyName) {
        this.allyName = allyName;
    }

    public String getAllyName() {
        return this.allyName;
    }

    //注册方法
    public void join(Observer obs) {
        System.out.println(obs.getName() + "加入" + this.allyName + "战队!");
        players.add(obs);
    }

    //注销方法
    public void quit(Observer obs) {
        System.out.println(obs.getName() + "退出" + this.allyName + "战队!");
        players.remove(obs);
    }

    //声明抽象通知方法
    public abstract void notifyObserver(String name);
}

//具体战队控制中心类:具体目标类
class ConcreteAllyControlCenter extends BaseAllyControlCenter {
    public ConcreteAllyControlCenter(String allyName) {
        System.out.println(allyName + "战队组建成功!");
        System.out.println("----------------------------");
        this.allyName = allyName;
    }

    //实现通知方法
    @Override
    public void notifyObserver(String name) {
        System.out.println(this.allyName + "战队紧急通知,盟友" + name + "遭受敌人攻击");
        //遍历观察者集合,调用每一个盟友(自己除外)的支援方法
        for (Object obs : players) {
            if (!((Observer) obs).getName().equalsIgnoreCase(name)) {
                ((Observer) obs).help();
            }
        }
    }
}

19.状态模式

状态模式定义如下

状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修 改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。

● Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状 态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态 类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时, 它是一个State子类的对象。
● State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在 抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状 态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写 在抽象状态类中。

● ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一 个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为 有所不同。

package com.example.demo.pattern.behavioral.state;

/**
 * 功能描述: 状态模式
 *  例子: 比如一个角色,拥有 人,恶魔,天使,三种状态,并对应三种不同的技能
 * @author luxiaomeng
 * @date 2020/9/7   10:52
 * 修改日志: 暂无
 */
public class StatePattern {
    public static void main(String[] args) {
        Role role = new Role();
        AngelState as = new AngelState();
        DevilState ds = new DevilState();
        PersonState ps = new PersonState();
        as.doAction(role);
        System.out.println("👆"+role.getState());
        ds.doAction(role);
        System.out.println("👆"+role.getState());
        ps.doAction(role);
        System.out.println("👆"+role.getState());
        /**
         * 天使技能:复活
         * 👆天使状态
         * 恶魔技能:灭世
         * 👆恶魔状态
         * 人形技能:帅
         * 👆人形状态
         */
    }
}

class Role {
    private State state;

    public Role(){
        state = null;
    }

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

    public State getState(){
        return state;
    }
}

interface State {
    public void doAction(Role role);
}
class AngelState implements State {

    @Override
    public void doAction(Role role) {
        System.out.println("天使技能:复活");
        role.setState(this);
    }

    @Override
    public String toString(){
        return "天使状态";
    }
}
class DevilState implements State {

    @Override
    public void doAction(Role role) {
        System.out.println("恶魔技能:灭世");
        role.setState(this);
    }

    @Override
    public String toString(){
        return "恶魔状态";
    }
}
class PersonState implements State {

    @Override
    public void doAction(Role role) {
        System.out.println("人形技能:帅");
        role.setState(this);
    }

    @Override
    public String toString(){
        return "人形状态";
    }
}

20.策略模式

在策略模式中,我们可以定义一些独立的类来封装不同的算法,每一个类封装一种具体的算 法,在这里,每一个封装算法的类我们都可以称之为一种策略(Strategy),为了保证这些策略 在使用时具有一致性,一般会提供一个抽象的策略类来做规则的定义,而每种算法则对应于 一个具体策略类。

在策略模式结构图中包含如下几个角色:

● Context(环境类):环境类是使用算法的角色,它在解决某个问题(即实现某个方法)时 可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策 略。
● Strategy(抽象策略类):它为所支持的算法声明了抽象方法,是所有策略类的父类,它可 以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具 体策略类中实现的算法。
● ConcreteStrategy(具体策略类):它实现了在抽象策略类中声明的算法,在运行时,具体策 略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。

package com.example.demo.pattern.behavioral.strategy;

/**
 * 功能描述: 策略模式
 * 例子描述:电影票根据不同的不同的角色,进行不同的折扣算法
 *
 * @author luxiaomeng
 * @date 2020/9/7   11:19
 * 修改日志: 暂无
 */
public class StrategyPattern {
    public static void main(String[] args) {
        MovieTicket mt = new MovieTicket();
        double originalPrice = 60.0;
        double currentPrice;
        mt.setPrice(originalPrice);
        System.out.println("原始价为:" + originalPrice);
        System.out.println("---------------------------------");
        Discount discount = new StudentDiscount();
        mt.setDiscount(discount);
        currentPrice = mt.getPrice();
        System.out.println("折后价为:" + currentPrice);
    }
}

//    电影票类:环境类
class MovieTicket {
    private double price;
    private Discount discount;    //维持一个对抽象折扣类的引用

    public void setPrice(double price) {
        this.price = price;
    }

    //    注入一个折扣类对象
    public void setDiscount(Discount discount) {
        this.discount = discount;
    }

    public double getPrice() {
//        调用折扣类的折扣价计算方法
        return discount.calculate(this.price);
    }
}

//折扣类:抽象策略类
interface Discount {
    public double calculate(double price);
}

//学生票折扣类:具体策略
class StudentDiscount implements Discount {
    @Override
    public double calculate(double price) {
        System.out.println("学生票:");
        return price * 0.8;
    }
}

//儿童票折扣类:具体策略类
class ChildrenDiscount implements Discount {
    @Override
    public double calculate(double price) {
        System.out.println("儿童票:");
        return price - 10;
    }
}

//VIP会员票折扣类:具体策略类
class VIPDiscount implements Discount {
    @Override
    public double calculate(double price) {
        System.out.println("VIP票:");
        System.out.println("增加积分!");
        return price * 0.5;
    }
}

21.模板方法模式

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

(1) AbstractClass(抽象类):在抽象类中定义了一系列基本操作(PrimitiveOperations),这些基 本操作可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中 可以重定义或实现这些步骤。同时,在抽象类中实现了一个模板方法(Template Method),用于 定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽 象类的子类中实现的基本方法,还可以调用其他对象中的方法。
(2) ConcreteClass(具体子类):它是抽象类的子类,用于实现在父类中声明的抽象基本操作 以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。

package com.example.demo.pattern.behavioral.template;

/**
 * 功能描述: 模板方法模式
 * 例子说明:同一个班的人同时先后一起参加期末考试(先考java,后考c),可是总分不一样
 *
 * @author luxiaomeng
 * @date 2020/9/7   11:38
 * 修改日志: 暂无
 */
public class TemplateMethodPattern {
    public static void main(String[] args) {
        A a = new A();
        a.play();
        B b = new B();
        b.play();
        System.out.println("a考了"+a.sum);
        System.out.println("b考了"+b.sum);
    }
}

/**
 * 抽象考试类
 */
abstract class AbstractExam {
    int sum ;
    abstract void java();

    abstract void c();

    // 模板方法
    public final void play() {
        // 先考java
        java();
        // 再考 c
        c();
    }
}

class A extends AbstractExam {

    @Override
    void java() {
        this.sum+=60;

    }

    @Override
    void c() {
        this.sum+=40;
    }
}
class B extends AbstractExam {
    @Override
    void java() {
        this.sum+=40;
    }

    @Override
    void c() {
        this.sum+=40;
    }
}

22.访问者模式

访问者模式(Visitor Pattern):提供一个作用于某对象结构中的各元素的操作表示,它使我们可以 在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。

在访问者模式结构图中包含如下几个角色:
●Vistor(抽象访问者):抽象访问者为对象结构中每一个具体元素类ConcreteElement声明一 个访问操作,从这个操作的名称或参数类型可以清楚知道需要访问的具体元素的类型,具体 访问者需要实现这些操作方法,定义对这些元素的访问操作。
●ConcreteVisitor(具体访问者):具体访问者实现了每个由抽象访问者声明的操作,每一个操 作用于访问对象结构中一种类型的元素。
●Element(抽象元素):抽象元素一般是抽象类或者接口,它定义一个accept()方法,该方法 通常以一个抽象访问者作为参数。【稍后将介绍为什么要这样设计。】
●ConcreteElement(具体元素):具体元素实现了accept()方法,在accept()方法中调用访问者 的访问方法以便完成对一个元素的操作。
●ObjectStructure(对象结构):对象结构是一个元素的集合,它用于存放元素对象,并且提 供了遍历其内部元素的方法。它可以结合组合模式来实现,也可以是一个简单的集合对象, 如一个List对象或一个Set对象。

package com.example.demo.pattern.behavioral.visitor;

import java.util.ArrayList;
import java.util.List;

/**
 * 功能描述: 参观者模式
 *  例子描述: 主管在群里,发布了奖励和惩罚信息,每个员工看到奖励和惩罚会开心和难过。
 *  a: 奖励
 *  b: 惩罚
 * @author luxiaomeng
 * @date 2020/9/7   14:17
 * 修改日志: 暂无
 */
public class VisitorPattern {
    public static void main(String[] args) {
        GoodMessage goodMessage = new GoodMessage();
        BadMessage badMessage = new BadMessage();
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.add(goodMessage);
        objectStructure.add(badMessage);
        A a = new A();
        objectStructure.action(a);
        B b = new B();
        objectStructure.action(b);
        //a:我太开心了
        //b:我太难过了

    }
}

abstract class Person {
    String name ;
    public abstract void feel(GoodMessage goodMessage);
    public abstract void feel(BadMessage badMessage);
}

class A  extends Person{
    public A() {
        this.name = "a";
    }

    @Override
    public void feel(GoodMessage goodMessage) {
        System.out.println("a:我太开心了");
    }

    @Override
    public void feel(BadMessage badMessage) {
        System.out.println("a:我太难过了");
    }
}
class B  extends Person{
    public B() {
        this.name = "b";
    }

    @Override
    public void feel(GoodMessage goodMessage) {
        System.out.println("b:我太开心了");
    }

    @Override
    public void feel(BadMessage badMessage) {
        System.out.println("b:我太难过了");
    }
}

/**
 *抽象元素角色- 主管发布的消息
 */
abstract class Message {
    // 被查看
    public abstract void accept(Person person);
}

class GoodMessage extends Message {
    @Override
    public void accept(Person person) {
        if ("a".equals(person.name)) {
            person.feel(this);
        }
    }
}
class BadMessage extends Message {
    @Override
    public void accept(Person person) {
        if ("b".equals(person.name)) {
            person.feel(this);
        }
    }
}

// 对象结构
class ObjectStructure {
    private List<Message> nodeList = new ArrayList<>();

    public void action(Person person) {
        for (Message message : nodeList) {
            message.accept(person);
        }
    }

    public void add(Message message) {
        this.nodeList.add(message);
    }

}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值