java实现面向对象的23种设计模式【超长预警,读完超过2小时】

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

前置内容
面对对象的七个设计原则,包括单一职责原则、开闭原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特原则、合成复用原则。

设计模式分类
创建型模式,包括单例、原型、工厂、抽象工厂、建造者 ,共5 种模式。

结构型模式,包括代理、适配器、桥梁、装饰、外观、享元、组合,共7 种模式。

行为型模式,包括模板方法、策略、命令、责任链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器 ,共11 种模式。

本文涉及一些简化的uml类图,用法可参照这篇博客,仅供参考。


设计原则
Design principles,设计模式就是实现了这些原则,从而达到了代码复用、增加可维护性的目的。

1、单一职责原则
Single Responsibility Principle(SRP),一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分。即一个类、接口、方法只负责一种职责。

2、开闭原则
Open Closed Principle(OCP),一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。需要做到用抽象构建框架,用实现扩展细节。

3、里氏替换原则
Liskov Substitution Principle(LSP),继承必须确保超类所拥有的性质在子类中仍然成立。

4、依赖倒置原则
Dependence Inversion Principle(DIP),高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程。

5、接口隔离原则
Interface Segregation Principle(ISP),要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。

6、迪米特原则
Law of Demeter(LoD),最少知道原则, 强调只和朋友说话,不和陌生人说话,这里的朋友指的是成员变量、方法的输入输出。如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。

7、合成复用原则
Composite Reuse Principle(CRP),它要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。



创造型模式

Creational Pattern,用于描述“怎样创建对象”,它的主要特点是“将对象的创建与使用分离”。

一、单例模式

Singleton Pattern,保证整个系统中一个类只有一个对象的实例,实现这种功能的方式就叫单例模式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第1张图片

1、懒汉式

public class Singleton {
    private static Singleton instance;

	private Singleton (){}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
} 

添加线程锁后:

public class Singleton {
    private static Singleton instance;

	private Singleton (){}

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

2、饿汉式

public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {
    }

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

3、双重校验锁

public class Singleton {
    private volatile static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

4、静态内部类

public class Singleton {
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    private Singleton() {
    }

    public static final Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}  

5、枚举

public enum Singleton {
    INSTANCE;

    public void method() {
    }
}

二、原型模式

Prototype Pattern,是用于创建重复的对象,同时又能保证性能。这种模式是实现了一个原型接口,用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。当直接创建对象的代价比较大时,则采用这种模式。

1、浅拷贝的原型模式
对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第2张图片
代码示例

public class Prototype implements Cloneable{
    private String name;
    private String info;

    public Prototype(String name, String info) {
        this.name = name;
        this.info = info;
    }

    @Override
    protected Prototype clone(){
        Prototype prototype=null;
        try {
            prototype = (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("克隆失败");
            e.printStackTrace();
        }
        return prototype;
    }

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

    public void show(){
        System.out.println(name+info);
    }
}
    public static void main(String[] args) {
        Prototype p1 = new Prototype("小美", "在遛狗");
        Prototype p2 = p1.clone();
        p2.setName("小华");
        p1.show();
        p2.show();
    }

2、带原型管理器的原型模式

java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第3张图片

代码示例

//多边形抽象类
public abstract class RegularPolygon implements Cloneable {
    protected String name;
    protected double side_length;

    public void setSide_length(float side_length) {
        this.side_length = side_length;
    }

    @Override
    protected Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("克隆失败");
            e.printStackTrace();
        }
        return clone;
    }

    abstract void show();
}

//正三角类
public class EquilateralTriangle extends RegularPolygon {
    public EquilateralTriangle() {
        this.name = "EquilateralTriangle";
    }

    @Override
    void show() {
        if (side_length==0){
            System.out.println("未指定边长");
        }else {
            double area = Math.sqrt(3) * Math.pow(side_length, 2) / 4;
            System.out.printf("边长为%.2f的正三角形,周长为%.2f,面积为%.2f\n",side_length,3*side_length,area);
        }
    }
}

//正方形类
public class Square extends RegularPolygon {
    public Square() {
        this.name = "Square";
    }

    @Override
    void show() {
        if (side_length==0){
            System.out.println("未指定边长");
        }else {
            double area = Math.pow(side_length, 2);
            System.out.printf("边长为%.2f的正方形,周长为%.2f,面积为%.2f\n",side_length,4*side_length,area);
        }
    }
}

//原型管理器
public class PrototypeManager {
    private HashMap<String, RegularPolygon> rps = new HashMap<String, RegularPolygon>();

    public PrototypeManager() {
        rps.put("EquilateralTriangle", new EquilateralTriangle());
        rps.put("Square", new Square());
    }

    public void addShape(String key, RegularPolygon rp) {
        rps.put(key, rp);
    }

    public RegularPolygon getShape(String key) {
        RegularPolygon rp = rps.get(key);
        return (RegularPolygon) rp.clone();
    }
}

    public static void main(String[] args) {
        PrototypeManager pm=new PrototypeManager();
        RegularPolygon rp1=(EquilateralTriangle)pm.getShape("EquilateralTriangle");
        rp1.setSide_length(1);
        rp1.show();
        Square rp2=(Square)pm.getShape("Square");
        rp2.setSide_length(1);
        rp2.show();
    }

3、深拷贝的原型模式
对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制。因Object类的clone方法只会拷贝对象中的基本的数据类型,故需要将原型模式中的数组、容器对象、引用对象等另行拷贝。当然,深拷贝的原型模式也可以结合原型管理器,这里不再赘述。

3.1、多层的浅复制
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第4张图片

//业务类
public class Prototype implements Cloneable {
    private String name;
    private String info;
    private SpaceTime spaceTime;

    public Prototype(String name, String info, SpaceTime spaceTime) {
        this.name = name;
        this.info = info;
        this.spaceTime = spaceTime;
    }

    @Override
    protected Prototype clone() {
        Prototype prototype = null;
        try {
            prototype = (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("克隆失败");
            e.printStackTrace();
        }
        return prototype;
    }

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

    public void setInfo(String info) {
        this.info = info;
    }

    public void setSpaceTime(SpaceTime spaceTime) {
        this.spaceTime = spaceTime;
    }

    public void show() {
        System.out.println(spaceTime.getWhen() + "," + name + "在" + spaceTime.getWhere() + info);
    }
}

//成员对象的类
public class SpaceTime implements Cloneable {
    private String when;
    private String where;

    public SpaceTime(String when, String where) {
        this.when = when;
        this.where = where;
    }

    public String getWhen() {
        return when;
    }

    public String getWhere() {
        return where;
    }

    public void setWhen(String when) {
        this.when = when;
    }

    public void setWhere(String where) {
        this.where = where;
    }

    @Override
    protected SpaceTime clone() throws CloneNotSupportedException {
        SpaceTime spaceTime = null;
        try {
            spaceTime = (SpaceTime) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("时空克隆失败");
            e.printStackTrace();
        }
        return spaceTime;
    }
}

    public static void main(String[] args) throws CloneNotSupportedException {
        SpaceTime spaceTime = new SpaceTime("昨天", "操场");
        Prototype p1 = new Prototype("小明", "跑步",spaceTime);
        
        Prototype p2 = p1.clone();
        p2.setName("小友");
        SpaceTime spaceTime2 = spaceTime.clone();
        spaceTime2.setWhen("今天");
        p2.setSpaceTime(spaceTime2);

        p1.show();
        p2.show();
    }

3.2、利用序列化进行深拷贝
经序列化,对象将保存于文件或缓冲区中。反序列化时,会一视同仁的注入各种类型结构,就实现了深复制,甚至进一步的可以持久化保存。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第5张图片

//业务类
public class Prototype implements Serializable {
    private String name;
    private String info;
    private SpaceTime spaceTime;

    public Prototype(String name, String info, SpaceTime spaceTime) {
        this.name = name;
        this.info = info;
        this.spaceTime = spaceTime;
    }

    public SpaceTime getSpaceTime() {
        return spaceTime;
    }

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

    public void setInfo(String info) {
        this.info = info;
    }

    public void setSpaceTime(SpaceTime spaceTime) {
        this.spaceTime = spaceTime;
    }

    public Prototype deepClone() throws IOException, ClassNotFoundException {
        // 将对象写入字节缓冲流中
        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bao);
        oos.writeObject(this);

        // 将对象从流中取出
        ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (Prototype) ois.readObject();
    }

    public void show() {
        System.out.println(spaceTime.getWhen() + "," + name + "在" + spaceTime.getWhere() + info);
    }
}

//成员对象的类
public class SpaceTime implements Serializable {
    private String when;
    private String where;

    public SpaceTime(String when, String where) {
        this.when = when;
        this.where = where;
    }

    public String getWhen() {
        return when;
    }

    public String getWhere() {
        return where;
    }

    public void setWhen(String when) {
        this.when = when;
    }

    public void setWhere(String where) {
        this.where = where;
    }
}

    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        SpaceTime spaceTime = new SpaceTime("昨天", "操场");
        Prototype p1 = new Prototype("小明", "跑步",spaceTime);

        Prototype p2 = p1.deepClone();
        p2.setName("小友");
        p2.getSpaceTime().setWhen("今天");
        
        p1.show();
        p2.show();
    }

三、工厂模式

Factory Pattern,工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

1、简单工厂模式
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第6张图片
代码举例

//快餐类
public abstract class Snack {
    protected abstract void produce();
}

//薯条类
public class Chips extends Snack {
    @Override
    protected void produce() {
        System.out.println("生产薯条");
    }
}

//汉堡类
public class Hamburger extends Snack{
    @Override
    protected void produce() {
        System.out.println("生产汉堡包");
    }
}

//快餐店类
public class Noshery{
    public static Snack getProduct(String command){
        Snack snack = null;
        try {
            if (command.equalsIgnoreCase("chips")) {
                snack = new Chips();
            } else if (command.equalsIgnoreCase("hamburger")) {
                snack = new Hamburger();
            } else {
                throw new ClassNotFoundException("不能生产该产品");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return snack;
    }
}

    public static void main(String[] args) {
        Noshery.getProduct("chips").produce();
        Noshery.getProduct("hamburger").produce();
    }

2、工厂方法模式
为实现开闭原则,增加一个全能类,形成工厂方法模式
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第7张图片
代码举例

//快餐
public abstract class Snack {
    protected abstract void produce();
}

//薯条
public class Chips extends Snack {
    @Override
    protected void produce() {
        System.out.println("生产薯条");
    }
}

//汉堡
public class Hamburger extends Snack{
    @Override
    protected void produce() {
        System.out.println("生产汉堡包");
    }
}

//快餐店接口
public interface Noshery{
    public abstract Snack make();
}

//汉堡制造者
public class HambugerMaker implements Noshery {
    @Override
    public Snack make() {
        return new Hamburger();
    }
}

//薯条制造者
public class ChipMaker implements Noshery {
    @Override
    public Snack make() {
        return new Chips();
    }
}

    public static void main(String[] args) {
        new HambugerMaker().make().produce();
        new ChipMaker().make().produce();
    }

四、抽象工厂模式

AbstractFactory Pattern,定义超级工厂类(厂商)以创造各种产品。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第8张图片
代码举例

//快餐
public abstract class Snack {
    protected abstract void produce();
}

//汉堡,肯德基汉堡,麦当劳汉堡
public abstract class Hamburger extends Snack {}

public class KHamburger extends Hamburger {
    @Override
    protected void produce() {
        System.out.println("你的肯德基汉堡");
    }
}

public class MHamburger extends Hamburger {
    @Override
    protected void produce() {
        System.out.println("你的麦当劳汉堡");
    }
}

//薯条,肯德基薯条,麦当劳薯条
public abstract class Chips extends Snack { }

public class KChips extends Chips {
    @Override
    protected void produce() {
        System.out.println("你的肯德基薯条");
    }
}

public class MChips extends Chips {
    @Override
    protected void produce() {
        System.out.println("你的麦当劳薯条");
    }
}

//快餐店
public abstract class Noshery{
    public abstract Chips getChip();
    public abstract Hamburger getHanmburger();
}

//肯德基、麦当劳
public class KFC extends Noshery{
    @Override
    public Chips getChip() {
        return new KChips();
    }

    @Override
    public Hamburger getHanmburger() {
        return new KHamburger();
    }
}

public class Mcdonald extends Noshery{
    @Override
    public Chips getChip() {
        return new MChips();
    }

    @Override
    public Hamburger getHanmburger() {
        return new  MHamburger();
    }
}

    public static void main(String[] args) {
        KFC kfc = new KFC();
        kfc.getChip().produce();
        kfc.getHanmburger().produce();
        System.out.println();
        Mcdonald mcdonald = new Mcdonald();
        mcdonald.getChip().produce();
        mcdonald.getHanmburger().produce();
    }

五、建造者模式

Builder Pattern,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,它使用多个简单的对象一步一步构建成一个复杂的对象。

java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第9张图片
1、传统的建造者模式

//电脑
public class Computer {
    private String CPU;
    private String GPU;
    private String harddisk;
    private String memory;
    private String powerSupply;
    private float price;

    /*
    * 这里省略了构造器和get、set方法
    * */
    
    public void show() {
        System.out.printf("主机:处理器-%s,显卡-%s,内存-%s,硬盘-%s,电源-%s,价格-%.0f元\n",
                CPU,GPU,memory,harddisk,powerSupply,price);
    }
}


//电脑建造者
public abstract class Builder {
    abstract void buildMainboard();
    abstract void buildCPU();
    abstract void buildGPU();
    abstract void buildMemory();
    abstract void buildPowerSupply();
    abstract void buildPrice();

    abstract Computer createPC();
}

//A电脑建造者
public class ABuilder extends Builder {
    private Computer PC = new Computer();

    @Override
    void buildCPU() {
        PC.setCPU("r9 3900x");
    }

    @Override
    void buildGPU() {
        PC.setGPU("RTX TITAN");
    }

    @Override
    void buildMemory() {
        PC.setMemory("芝奇皇家戟 16g*4");
    }

    @Override
    void buildHarddisk() {
        PC.setHarddisk("三星evo 1T*2");
    }

    @Override
    void buildPowerSupply() {
        PC.setPowerSupply("1200W");
    }

    @Override
    void buildPrice() {
        PC.setPrice(59999);
    }

    @Override
    Computer createPC() {
        return PC;
    }
}


//B电脑建造者 BBuilder
/*
*	因与A类似,在此省略
*/

//建造指导者
public class Director {
    private Builder builder = null;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public Computer construct() {
        builder.buildCPU();
        builder.buildGPU();
        builder.buildHarddisk();
        builder.buildMemory();
        builder.buildPowerSupply();
        builder.buildPrice();
        return builder.createPC();
    }
}

    public static void main(String[] args) {
        Director d1 = new Director(new ABuilder());
        Computer pc_a = d1.construct();
        pc_a.show();

        Director d2 = new Director(new BBuilder());
        Computer pc_b = d2.construct();
        pc_b.show();
    }

2、静态内部类建造者

//电脑类
public class Computer {
    private String CPU;
    private String GPU;
    private String harddisk;
    private String memory;
    private String powerSupply;
    private float price;

    public Computer(Builder builder) {
        this.CPU = builder.CPU;
        this.GPU = builder.GPU;
        this.harddisk = builder.harddisk;
        this.memory = builder.memory;
        this.powerSupply = builder.powerSupply;
        this.price = builder.price;
    }

    //内部类--建造者
    public static class Builder {
        private String CPU;
        private String GPU;
        private String harddisk;
        private String memory;
        private String powerSupply;
        private float price;

        public Builder setCPU(String CPU) {
            this.CPU = CPU;
            return this;
        }

        public Builder setGPU(String GPU) {
            this.GPU = GPU;
            return this;
        }

        public Builder setHarddisk(String harddisk) {
            this.harddisk = harddisk;
            return this;
        }

        public Builder setMemory(String memory) {
            this.memory = memory;
            return this;
        }

        public Builder setPowerSupply(String powerSupply) {
            this.powerSupply = powerSupply;
            return this;
        }

        public Builder setPrice(float price) {
            this.price = price;
            return this;
        }

        public Computer build() {
            return new Computer(this);
        }
    }

    public void show() {
        System.out.printf("主机:处理器-%s,显卡-%s,内存-%s,硬盘-%s,电源-%s,价格-%.0f元\n",
                CPU,GPU,memory,harddisk,powerSupply,price);
    }
}

    public static void main(String[] args) {
        Computer pc = new Computer.Builder().
                setCPU("r9 3900x").setGPU("RTX TITAN").
                setHarddisk("芝奇皇家戟 16g*4").setMemory("三星evo 1T*2").
                setPowerSupply("1200W").setPrice(59999).
                build();
        pc.show();
    }

结构型模式

Structural Pattern,用于描述如何将类或对象按某种布局组成更大的结构

一、代理模式

Proxy Pattern,为其他对象提供一种代理以控制对这个对象的访问。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。

1、静态代理:
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第10张图片

//演员接口
public interface Actor {
    public void perform();
}

//明星类
public class Star implements Actor {
    @Override
    public void perform() {
        System.out.println("演员有意向演出");
    }
}

//经纪人类
public class Agent implements Actor {
    private Actor actor;

    public Agent(Actor actor) {
        this.actor = actor;
    }

    @Override
    public void perform() {
        Random rand = new Random();
        if (rand.nextBoolean()) {
            System.out.println("经纪人正在联系...");
            actor.perform();
        }
        else {
            System.out.println("经纪人告诉你,她没有档期");
        }
    }
}

    public static void main(String[] args) {
        Star star = new Star();
        Agent agent = new Agent(star);

        agent.perform();
    }

2、动态代理:
代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象,代理类和被代理对象不需要实现同一接口,但被代理类仍需要实现接口或继承父类。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第11张图片

//演员接口
public interface Actor {
    public int perform();

    public void meeting();
}

//明星类
public class Star implements Actor {

    @Override
    public int perform() {
        Random rand = new Random();
        if (rand.nextBoolean()) {
            System.out.println("接受演出邀约");
            return 1;
        }
        else {
            System.out.println("拒绝邀请");
            return -1;
        }
    }

    @Override
    public void meeting() {
        System.out.println("the actor will have a meeting with you");
    }
}

//经纪人类----需要实现InvocationHandler
public class Agent implements InvocationHandler {
    private Actor actor;

    public Agent(Actor actor) {
        this.actor = actor;
    }

    /**
     * @param proxy  代理对象
     * @param method 正在调用的方法
     * @param args   方法的参数
     * @return 就是被代理类的返回值
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("perform")) {
            return (int) method.invoke(actor, args);
        } else if (method.getName().equals("meeting")) {
            return method.invoke(actor, args);
        }else {
            return null;
        }
    }
}

    public static void main(String[] args) {
        Star star = new Star();
        Agent agent = new Agent(star);

        /**
         * 实现java.lang.reflect.Proxy类
         *Proxy.newProxyInstance创建的代理对象是在jvm运行时动态生成的一个对象
         * 第一个参数,ClassLoader对象来加载我们的代理对象
         * 第二个参数,为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
         * 第三个参数,将这个代理对象关联到了上方的 InvocationHandler 这个对象上
         */
        Actor proxy = (Actor) Proxy.newProxyInstance(agent.getClass().getClassLoader(), star.getClass().getInterfaces(), agent);
        if (proxy.perform() == 1) {
            proxy.meeting();
        }
    }

3、CGLIB代理:
CGLib通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,可以实现无接口类的代理。但因为采用的是继承,所以不能对final修饰的类进行代理。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第12张图片
需要先导入相关依赖

    <dependency>
      <groupId>asmgroupId>
      <artifactId>asmartifactId>
      <version>3.3.1version>
    dependency>
    <dependency>
      <groupId>asmgroupId>
      <artifactId>asm-commonsartifactId>
      <version>3.3.1version>
    dependency>
    <dependency>
      <groupId>asmgroupId>
      <artifactId>asm-treeartifactId>
      <version>3.3.1version>
    dependency>
    
    <dependency>
      <groupId>cglibgroupId>
      <artifactId>cglibartifactId>
      <version>2.2.2version>
    dependency>
    
//明星类
public class Star {
    public int perform() {
        Random rand = new Random();
        if (rand.nextBoolean()) {
            System.out.println("接受演出邀约");
            return 1;
        }
        else {
            System.out.println("没有档期,拒绝邀请");
            return -1;
        }
    }

    public void meeting() {
        System.out.println("the actor will have a meeting with you");
    }
}

//经纪人类----实现MethodInterceptor,即Cglib子类代理
public class Agent implements MethodInterceptor {
    private Star star;

    public Agent(Star star) {
        this.star = star;
    }

    //为目标类类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用
    public Object getProxyInstance() {
        Enhancer en = new Enhancer();
        en.setSuperclass(star.getClass());
        en.setCallback(this);
        return en.create();
    }

    /**
     * @param obj CGLib动态生成的代理类实例
     * @param method 正在调用的方法
     * @param args   方法的参数
     * @param proxy 代理类对方法的代理引用
     * @return 被代理类的返回值
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        if (method.getName().equals("perform")) {
            return (int) method.invoke(star, args);
        } else if (method.getName().equals("meeting")) {
            return method.invoke(star, args);
        } else {
            return null;
        }
    }
}

    public static void main(String[] args) {
        //目标对象
        Star star = new Star();

        //代理对象
        Star proxy = (Star)new Agent(star).getProxyInstance();

        //执行代理对象的方法
        if (proxy.perform() == 1) {
            proxy.meeting();
        }
    }

二、适配器模式

Adapter Pattern,将一个类的接口转换成客户希望的另外一个接口,它是作为两个不兼容的接口之间的桥梁。这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。

1、类适配器
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第13张图片

//输入220V交流电
public class DC220 {
    public String supply_DC(){
        return "DC220";
    }
}

//目标直流电
public interface AC {
    public String suply_AC();
}

//电源适配器转电压
//继承源类型,实现目标接口。
public class Adapter extends DC220 implements AC {
    @Override
    public String suply_AC() {
        return "AC5";
    }
}

//手机
public class Phone {
    private String input_voltage;

    public Phone(String input_voltage) {
        this.input_voltage = input_voltage;
    }

    public void status() {
        if (this.input_voltage.equalsIgnoreCase("AC5")) {
            System.out.println("充电电压正常");
        } else {
            System.out.println("充电电压异常");
        }
    }
}

    public static void main(String[] args) {
        Adapter voltage = new Adapter();
        new Phone(voltage.suply_AC()).status();
    }

2、对象适配器
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第14张图片

//输入220V交流电
public class DC220 {
    public String supply_DC(){
        return "DC220";
    }
}

//目标直流电
public interface AC {
    public String suply_AC();
}

//电源适配器转电压
//设置源类型的属性,实现目标接口。
public class Adapter implements AC {
    private DC220 input;

    public Adapter(DC220 input) {
        this.input = input;
    }

    @Override
    public String suply_AC() {
        if (input == null) {
            return "";
        }
        return "AC5";
    }
}

//手机
public class Phone {
    private String input_voltage;

    public Phone(String input_voltage) {
        this.input_voltage = input_voltage;
    }

    public void status() {
        if (this.input_voltage.equalsIgnoreCase("AC5")) {
            System.out.println("充电电压正常");
        } else {
            System.out.println("充电电压异常");
        }
    }
}


    public static void main(String[] args) {
        DC220 input = new DC220();
        Adapter adapter = new Adapter(input);
        new Phone(adapter.suply_AC()).status();
    }

三、桥梁模式

Bridge Pattern,将抽象部分与它的实现部分分离,使它们都可以独立地变化,来实现二者的解耦。这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第15张图片

//形状---Abstraction,抽象类
public abstract class Shape {
    protected Color color ;

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

    public abstract void show();
}

//圆---RefindAbstraction扩展的抽象类
public class Circle extends Shape {
    public Circle(Color color) {
        this.color = color;
    }

    @Override
    public void show() {
        color.color();
        System.out.println("圆");
    }
}

//正方形---RefindAbstraction扩展的抽象类
public class Square extends Shape {
   //类似圆形,不再赘述
}

//颜色---Implementor实现者
public interface Color {
    public void color();
}

//红色---ConcreteImplementor具体实现
public class Red implements Color {
    @Override
    public void color() {
        System.out.print("这是红色的");
    }
}

//绿色---ConcreteImplementor具体实现
public class Green implements Color {
    //类似红色,不再赘述
}

    public static void main(String[] args) {
        Circle a = new Circle(new Red());
        a.show();
        a.setColor(new Green());
        a.show();

        //正方形类似,不再列举
    }

以上例子可能不够有代表性,这里说明下jdbc的桥梁模式结构,它相对来说较特殊,可以这么理解:
jdbc api为抽象部分的接口,而应用程序为扩展的抽象接口;Driver类其具体实现就是实现部分的角色。这样应用编程和数据库操作两者可以分离开,而中间起桥接作用的就是既使用了jdbcAPI,又关联了Driver的DriverManager

java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第16张图片


四、装饰模式

Decorator Pattern,动态地给一个对象添加一些额外的职责。它是作为现有的类的一个包装,允许向一个现有的对象添加新的功能,同时又不改变其结构。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第17张图片

//角色接口
public interface Role {
    public void show();
}

//战士角色
public class Warrior implements Role{
    private String name;

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

    @Override
    public void show() {
        System.out.println("战士"+name);
    }
}

//装饰类
public abstract class Decorate implements Role {
    private Role role;

    public Decorate(Role role) {
        this.role = role;
    }

    public Role getRole() {
        return role;
    }
}

//新增技能A
public class AddWorriorSkill_A extends Decorate{
    public AddWorriorSkill_A(Warrior worrior) {
        super(worrior);
    }

    public void skill_A(){
        System.out.println("\t获得技能回天返日,两秒内恢复当前已损血量");
    }

    @Override
    public void show() {
        this.getRole().show();
        skill_A();
    }
}

//新增武器A
public class AddWorriorWeapon_A extends Decorate{
    public AddWorriorWeapon_A(Warrior worrior) {
        super(worrior);
    }

    public void weapon_A(){
        System.out.println("\t获得武器屠龙刀,攻击力999、耐久度999");
    }

    @Override
    public void show() {
        this.getRole().show();
        weapon_A();
    }
}

    public static void main(String[] args) {
        Warrior warrior = new Warrior("龙傲天");
        new AddWorriorSkill_A(warrior).show();
        new AddWorriorWeapon_A(warrior).show();
    }

五、外观模式

Facade Pattern,为子系统中的一组接口提供一个一致的界面了,并隐藏系统的复杂性。这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第18张图片

//画
public interface Painting {
    public void draw();
}

//油画
public class OilPainting implements Painting {
    @Override
    public void draw() {
        System.out.println("画家画了一幅油画");
    }
}

//水墨画
public class BrushPainting implements Painting {
    @Override
    public void draw() {
        System.out.println("画家画了一幅水墨画");
    }
}

//画家
public class Painter {
    private Painting brushPainting;
    private Painting oilPainting;

    public Painter() {
        this.brushPainting = new  BrushPainting();
        this.oilPainting = new OilPainting();
    }

    public void drawBrushPainting() {
        brushPainting.draw();
    }

    public void drawOilPainting() {
        oilPainting.draw();
    }
}

    public static void main(String[] args) {
        Painter painter = new Painter();
        painter.drawBrushPainting();
        painter.drawOilPainting();
    }

六、享元模式

Flyweight Pattern,采用一个共享类来避免大量拥有相同内容的“小类”的开销,它提供了减少对象数量从而改善应用所需的对象结构的方式。享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第19张图片

//文件
public interface Document {
    public void print();
}

//具体文件类
public class ConcretetDoucument implements Document{
    private String name;

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

    public String getName() {
        return name;
    }

    @Override
    public void print() {
        System.out.println("打印文件:"+name);
    }
}

//文件夹
public class Folder {
    private Map<String, Document> files = new HashMap<>();

    public Document getFile(String name){
        if (!files.containsKey(name)) {
            files.put(name, new ConcretetDoucument(name));
        }
        return files.get(name);
    }
}

    public static void main(String[] args) {
        Folder folder = new Folder();

        folder.getFile("人工智能").print();

        Document a = folder.getFile("机器学习");
        Document b = folder.getFile("机器学习");
        if(a==b){
            System.out.println("a与b共享变量");
        }
    }

复合享元,即享元组成享元,虽然复合享元对象本身不能共享,但它们可以分解成单纯享元对象再被共享。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第20张图片

//文件
public interface Document {
    public void print();
}

//具体文件类
public class ConcretetDoucument implements Document {
    private String name;

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

    @Override
    public void print() {
        System.out.println("打印:" + name);
    }
}

//复合享元类,可视为子文件夹
//子文件夹内按照分类有各种享元组合
public class ConcreteCompositeDocument implements Document {
    private Map<String, Document> subFolders = new HashMap<>();

    public void add(String className, Document file) {
        subFolders.put(className, file);
    }

    @Override
    public void print() {
        subFolders.forEach((k, v) -> {
            System.out.print(k + "类文件中,");
            v.print();
        });
    }
}

//文件夹----享元工厂类
public class Folder {
    private Map<String, Document> files = new HashMap<>();

    public Document factory(String className, List<String> names) {
        ConcreteCompositeDocument subfolder = new ConcreteCompositeDocument();
        for (String name : names) {
            subfolder.add(className, this.factory(name));
        }
        return subfolder;
    }

    public Document factory(String name) {
        if (!files.containsKey(name)) {
            files.put(name, new ConcretetDoucument(name));
        }
        return files.get(name);
    }
}

    public static void main(String[] args) {
        Folder folder = new Folder();

        folder.factory("生物",Arrays.asList("生物神经网络","植物学","昆虫记")).print();

        Document folder1 = folder.factory("计算机", Arrays.asList("数据结构与算法", "计算机组成原理", "操作系统"));
        Document folder2 = folder.factory("计算机", Arrays.asList("数据结构与算法", "计算机组成原理", "操作系统"));
        if (folder1 != folder2) {
            System.out.println("复合享元本体无法共享");
        }
    }

七、组合模式

Composite Pattern,将对象以树形结构组织起来,以达成“部分-整体”的层次结构,
使得客户端对单个对象和组合对象的使用具有一致性。这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第21张图片

//抽象类
public abstract class Component {
    protected String name;

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

    public abstract void show();
}

//节点
public class Composite extends Component {
    private Set<Component> children = new HashSet<>();

    public Composite(String name) {
        super(name);
    }

    public void add(Component component) {
        children.add(component);
    }

    public void remove(Component component) {
        children.remove(component);
    }

	//这里名字相同视为了同一节点
    public void remove(Component component) {
        children.removeIf(x -> 
            x.name == component.name
        );
    }

    @Override
    public void show() {
        System.out.print("(节点" + name + " -> ");
        children.forEach(x -> {
            x.show();
        });
        System.out.print(")  ");
    }
}

//叶子节点
public class Leaf extends Component {
    public Leaf(String name) {
        super(name);
    }

    @Override
    public void show() {
        System.out.print("叶子节点" + name + " ");
    }
}

    public static void main(String[] args) {
        Composite root = new Composite("root");
        Composite a = new Composite("a");
        Leaf b = new Leaf("b");
        Leaf c = new Leaf("c");

        root.add(a);
        root.add(b);
        a.add(c);

        root.show();
    }

行为型模式

Behavioral Pattern,用于描述类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,以及怎样分配职责。

一、模板方法模式

Template Method Pattern,定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。在模板模式中,一个抽象类公开定义了执行它的方法的方式/模板,它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第22张图片

//玩游戏的模板方法
public abstract class PlayGame {
    protected abstract void login();

    protected abstract void play();

    protected void end() {
        System.out.println("关闭游戏");
    }

    //以final修饰,不允许子类改方法执行顺序
    protected final void playGame() {
        login();
        play();
        end();
    }
}

//玩LOL
public class PlayLOL extends PlayGame {
    @Override
    protected void login() {
        System.out.println("登录WeGame平台");
    }

    @Override
    protected void play() {
        System.out.println("玩LOL");
    }
}

//玩DOTA
public class PlayDOTA extends PlayGame {
    @Override
    protected void login() {
        System.out.println("登录Steam平台");
    }

    @Override
    protected void play() {
        System.out.println("玩DOTA2");
    }
}

    public static void main(String[] args) {
        new PlayDOTA().playGame();
        System.out.println();
        new PlayLOL().playGame();
    }

二、策略模式

Strategy Pattern,主要是定义一系列的算法,把这些算法一个个封装成拥有共同接口的单独的类,并且使它们之间可以互换。在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第23张图片

//旅行策略接口
public interface TravelStrategy {
    public void travel();
}

//旅行具体方式---具体策略:火车、飞机
public class TravelByTrain implements TravelStrategy {
    @Override
    public void travel() {
        System.out.println("坐火车去旅行");
    }
}

public class TravelByPlane implements TravelStrategy {
    @Override
    public void travel() {
        System.out.println("坐飞机去旅行");
    }
}

//上下文类
public class Context {
    TravelStrategy strategy;

    public Context(TravelStrategy strategy) {
        this.strategy = strategy;
    }

    public void strategy() {
        strategy.travel();
    }
}

    public static void main(String[] args) {
        new Context(new TravelByTrain()).strategy();
        new Context(new TravelByPlane()).strategy();
    }

三、命令模式

Command Pattern,将一个请求封装为一个对象,请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。调用者和接受者之间完全解耦,可以动态地对请求进行参数化、队列化和日志化等操作,且可以不同命令组成复合命令。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第24张图片

//智能音箱类
public class SmartSpeaker {
    public void playMusic() {
        System.out.println("智能音箱正在为您播放音乐");
    }

    public void broadcastNews() {
        System.out.println("智能音箱正在为您播报新闻");
    }

    public void weatherForecast() {
        System.out.println("智能音箱正在为您预报天气");
    }
}

//命令接口
public  interface Command {
    public void execute();
}

//开音乐命令
public class MusicPlayCommand implements Command {
    private SmartSpeaker sound = new SmartSpeaker();

    @Override
    public void execute() {
        sound.playMusic();
    }
}

//播新闻命令
public class NewsPlayCommand implements Command {
    private SmartSpeaker sound = new SmartSpeaker();

    @Override
    public void execute() {
        sound.broadcastNews();
    }
}

//开天气预报命令
public class WeatherForecastCommand implements Command {
    private SmartSpeaker sound = new SmartSpeaker();

    @Override
    public void execute() {
        sound.weatherForecast();
    }
}

//宏命令类---即将命令复合并最终可一起操作
public class MacroCommand implements Command {
    List<Command> commands = new ArrayList<>();

    public MacroCommand add(Command command) {
        commands.add(command);
        return this;
    }

    //这里的remove需要同样的对象
    public MacroCommand remove(Command command) {
        commands.remove(command);
        return this;
    }

    @Override
    public void execute() {
        commands.forEach(Command::execute);
    }
}

//调用者类
public class Invoker {
    private Command musicCommand;
    private Command newsCommand;
    private Command forecastCommand;
    private Command macroCommand;

	//set方法结合了建造模式,方便调用
    public Invoker setMusicCommand(MusicPlayCommand musicCommand) {
        this.musicCommand = musicCommand;
        return this;
    }

    public Invoker setNewsCommand(NewsPlayCommand newsCommand) {
        this.newsCommand = newsCommand;
        return this;
    }

    public Invoker setForecastCommand(WeatherForecastCommand forecastCommand) {
        this.forecastCommand = forecastCommand;
        return this;
    }

    public Invoker setMacroCommand(MacroCommand macroCommand) {
        this.macroCommand = macroCommand;
        return this;
    }

    public void playMusic() {
        musicCommand.execute();
    }

    public void broadcastNews() {
        newsCommand.execute();
    }

    public void weatherForecast() {
        forecastCommand.execute();
    }

    public void composite() {
        macroCommand.execute();
    }
}

    public static void main(String[] args) {
        Invoker invoker = new Invoker();

        MusicPlayCommand a = new MusicPlayCommand();
        NewsPlayCommand b = new NewsPlayCommand();
        WeatherForecastCommand c = new WeatherForecastCommand();
        MacroCommand macroCommand = new MacroCommand();

        macroCommand.add(a).add(b).add(c).remove(c);
        invoker.setMusicCommand(a).setNewsCommand(b).setForecastCommand(c).setMacroCommand(macroCommand);

        invoker.playMusic();
        invoker.broadcastNews();
        invoker.weatherForecast();

        System.out.println();

        invoker.composite();
    }

四、责任链模式

Chain of Responsibility Pattern,使多个对象都有机会处理请求,从而避免请求的发送
者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第25张图片

//请假请求
public class LeaveRequest {
    private int leaveDays;

    public LeaveRequest(int leaveDays) {
        this.leaveDays = leaveDays;
    }

    public void setLeaveDays(int leaveDays) {
        this.leaveDays = leaveDays;
    }

    public int getLeaveDays() {
        return leaveDays;
    }
}

//管理者类,即Handler
public abstract class Manager {
    protected Manager next;
    protected int handleDays;
    protected String name;

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

    public void setHandleDays(int handleDays) {
        this.handleDays = handleDays;
    }

    public abstract void handleRequest(int days);
}

//分别是,班主任可处理三天假条、辅导员可处理两周假条
//本例其实班主任和辅导员类可以合并为一种,但考虑可以各自有其它功能,就把他们分开了
public class ClassTeacher extends Manager {
    public ClassTeacher() {
        this.handleDays = 3;
        this.name = "班主任";
    }

    public ClassTeacher(Manager next) {
        this.next = next;
        this.handleDays = 3;
        this.name = "班主任";
    }

    @Override
    public void handleRequest(int days) {
        if (days <= this.handleDays) {
            System.out.println(name+"已为你处理了"+days+"天的请假要求");
            return;
        }
        if (next != null) {
            System.out.println(name+"无法处理,已经移交给"+next.name);
            this.next.handleRequest(days);
        } else {
            System.out.println(name+"暂时无法为你处理"+days+"天的请假要求,请继续找上级领导");
        }
    }
}

public class Counselor  extends Manager{
    public Counselor() {
        this.handleDays = 14;
        this.name = "辅导员";
    }

    public Counselor(Manager next) {
        this.next=next;
        this.handleDays = 14;
        this.name = "辅导员";
    }

    @Override
    public void handleRequest(int days) {
        if (days <= this.handleDays) {
            System.out.println(name+"已为你处理了"+days+"天的请假要求");
            return;
        }
        if (next != null) {
            System.out.println(name+"无法处理,已经移交给"+next.name);
            this.next.handleRequest(days);
        } else {
            System.out.println(name+"暂时无法为你处理"+days+"天的请假要求,请继续找上级领导");
        }
    }
}

    public static void main(String[] args) {
        LeaveRequest leaveRequest = new LeaveRequest(1);

        ClassTeacher classTeacher = new ClassTeacher();
        Counselor counselor = new Counselor();
        classTeacher.setNext(counselor);

        classTeacher.handleRequest(leaveRequest.getLeaveDays());
        System.out.println();
        leaveRequest.setLeaveDays(20);
        classTeacher.handleRequest(leaveRequest.getLeaveDays());
    }

五、状态模式

State Pattern,允许一个对象在其内部状态改变时改变它的行为。在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第26张图片

//订单---即Context
public class Order {
     State newState = new New(this);
     State canceledState = new Canceled(this);
     State processingState = new UnderWay(this);
     State completedState = new Completed(this);

     State currentState = newState;

     //改变订单状态
    public void setCurrentState(State currentState) {
        this.currentState = currentState;
    }

    //订单的各类操作,不同状态下不同
    public void cancel() {
        currentState.cancel();
    }

    public void pay() {
        currentState.pay();
    }

    public void confirm() {
        currentState.confirm();
    }

    //查看订单状态
    public void show() {
        currentState.show();
    }
}

//订单状态接口
public interface State {
    public void cancel();

    public void pay();

    public void confirm();

    public void show();
}

//订单刚新建
public class New implements State {
    Order order;

    public New(Order order) {
        this.order = order;
    }

    @Override
    public void cancel() {
        order.setCurrentState(order.canceledState);
        System.out.println("订单已取消");
    }

    @Override
    public void pay() {
        order.setCurrentState(order.processingState);
        System.out.println("订单已付款");
    }

    @Override
    public void confirm() {
        System.out.println("订单未付款,无法确认订单");
    }

    @Override
    public void show() {
        System.out.println("订单当前为新建状态,请即使付款");
    }
}

//订单已取消
public class Canceled implements State {
    Order order;

    public Canceled(Order order) {
        this.order = order;
    }

    @Override
    public void cancel() {
        System.out.println("订单已取消,无法操作");
    }

    @Override
    public void pay() {
        System.out.println("订单已取消,无法操作");
    }

    @Override
    public void confirm() {
        System.out.println("订单已取消,无法操作");
    }

    @Override
    public void show() {
        System.out.println("该订单已取消");
    }
}

//订单正在交易中
public class UnderWay implements State {
    Order order;

    public UnderWay(Order order) {
        this.order = order;
    }

    @Override
    public void cancel() {
        order.setCurrentState(order.canceledState);
        System.out.println("订单已取消,款项已退回");
    }

    @Override
    public void pay() {
        System.out.println("订单已完成付款,请勿重复操作");
    }

    @Override
    public void confirm() {
        order.setCurrentState(order.completedState);
        System.out.println("订单已确认完成");
    }

    @Override
    public void show() {
        System.out.println("订单正在送达途中,收货后请即使确认");
    }
}

//订单完成
public class Completed implements State {
    Order order;

    public Completed(Order order) {
        this.order = order;
    }

    @Override
    public void cancel() {
        System.out.println("订单已完成,无法取消,请走售后渠道反馈需求");
    }

    @Override
    public void pay() {
        System.out.println("订单已完成,请勿再操作");
    }

    @Override
    public void confirm() {
        System.out.println("订单已完成,请勿再操作");
    }

    @Override
    public void show() {
        System.out.println("已确认订单,钱货两清,订单完成。");
    }
}

    public static void main(String[] args) {
        Order order = new Order();

        order.pay();
        order.show();
        System.out.println();
        order.cancel();
        order.show();
    }

六、观察者模式

Observer Pattern,定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。比如,当一个对象被修改时,则会自动通知依赖它的对象。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第27张图片

//贸易影响因素,即贸易需要观察的对象
public abstract class AffectingFactors {
    protected List<FactorObserver> observers = new ArrayList<>();

    public abstract void addObserver(FactorObserver observer);

    public abstract void removeObserver(FactorObserver observer);

    protected void notifyObserver(int change){
        observers.forEach(x->x.influence(change));
    }
}

//本币汇率
public class DomesticCurrency extends AffectingFactors {
    public void rateIncrease() {
        notifyObserver(1);
    }

    public void rateDecrease() {
        notifyObserver(-1);
    }

    @Override
    public void addObserver(FactorObserver observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(FactorObserver observer) {
        observers.remove(observer);
    }
}

//观察者接口
public interface FactorObserver {
    public void influence(int change);
}

//进口贸易
public class ImportTrade implements FactorObserver{
    @Override
    public void influence(int change) {
        if (change > 0) {
            System.out.println("因本币升值,进口贸易利润增加");
        } else {
            System.out.println("因本币贬值,进口贸易利润减少");
        }
    }
}

//出口贸易
public class ExportTrade implements FactorObserver{
    @Override
    public void influence(int change) {
        if (change > 0) {
            System.out.println("因本币升值,出口贸易利润减少");
        } else {
            System.out.println("因本币贬值,出口贸易利润增加");
        }
    }
}

    public static void main(String[] args) {
        DomesticCurrency rate = new DomesticCurrency();

        rate.addObserver(new ImportTrade());
        rate.addObserver(new ExportTrade());

        rate.rateDecrease();
        System.out.println();
        rate.rateIncrease();
    }

七、中介者模式

Mediator Pattern,用一个调停对象来封装一系列的对象交互。这种模式提供了一个中介类,该类通常处理不同类之间的通信,使得多个对象和类之间的通信复杂性降低。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第28张图片

//本例是个体通过房产中介租房,买家和卖家直接交互信息,简化多个类之间交互信息的方式。
//房产中介抽象类---即类图中的Mediator
public abstract class Mediator {
    //注册自己的服务对象(客户们)
    public abstract void register(Customer customer);

    //转发租房需求信息给所有出租者
    public abstract void send2Renters(String sender, String message);

    //转发租房需求信息给所有找房者
    public abstract void send2AllLessee(String sender, String message);

    //转发出租者的回复信息给单个找房子的人
    public abstract void send2Lessee(String sender, String message, String receiver);
}

//具体的某中介公司
public class ConcreteMediator extends Mediator {
    private HashMap<String, Customer> renterRegisters = new HashMap<String, Customer>();
    private HashMap<String, Customer> lesseeRegisters = new HashMap<String, Customer>();

    @Override
    public void register(Customer customer) {
        if (customer.getClass().getSimpleName().contains("Renter")) {
            renterRegisters.put(customer.getId(), customer);
        } else if (customer.getClass().getSimpleName().equals("Lessee")) {
            lesseeRegisters.put(customer.getId(), customer);
        }
        customer.setMediator(this);
    }

    public void register(Customer...customers) {
        for (Customer customer : customers) {
            register(customer);
        }
    }

    @Override
    public void send2Renters(String sender, String message) {
        renterRegisters.values().forEach(x->x.receive(sender,message));
    }

    @Override
    public void send2AllLessee(String sender, String message) {
        lesseeRegisters.values().forEach(x->x.receive(sender,message));
    }

    @Override
    public void send2Lessee(String sender, String message, String receiver) {
        lesseeRegisters.get(receiver).receive(sender, message);
    }
}

//中介的客户,包含租户和房东---对应类图中的Colleague
//它的具体实现类的send和receive方法可以有较多扩展,这里简化了。
public abstract class Customer {
    protected String id;
    protected Mediator mediator;

    public String getId() {
        return id;
    }

    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    public abstract void receive(String sender, String message);

    public abstract void send(String message);
}

//房东
public abstract class Renter extends Customer {
    public abstract void action(String sender, String message);
}

//出租单间的房东
public class SingleRoomRenter extends Renter {
    public SingleRoomRenter(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    @Override
    public void action(String sender, String message) {
        if (message.contains("单间")) {
            System.out.println(id + "回复" + sender + "可以找我的房子");
            this.send("可以找我的房子", sender);
        }
        System.out.println();
    }

    @Override
    public void receive(String sender, String message) {
        System.out.println(id + "收到" + sender + "的信息");
        action(sender, message);
    }

    @Override
    public void send(String message) {
        this.mediator.send2AllLessee(id, message);
    }

    public void send(String message, String receiver) {
        this.mediator.send2Lessee(id, message, receiver);
    }
}

//出租套间的房东
public class ApartmentRenter extends Renter {
    public ApartmentRenter(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    @Override
    public void action(String sender, String message) {
        if (message.contains("套间")) {
            System.out.println(id + "回复" + sender + "可以找我的房子");
            this.send("可以找我的房子", sender);
        }
        System.out.println();

    }

    @Override
    public void receive(String sender, String message) {
        System.out.println(id + "收到" + sender + "的信息");
        action(sender, message);
    }

    @Override
    public void send(String message) {
        this.mediator.send2AllLessee(id, message);
    }

    public void send(String message, String receiver) {
        this.mediator.send2Lessee(id, message, receiver);
    }
}

//租户
public class Lessee extends Customer {
    public Lessee(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    @Override
    public void receive(String sender, String message) {
        System.out.println(id + "收到" + sender + "的信息");
    }

    @Override
    public void send(String message) {
        this.mediator.send2Renters(this.id, message);
    }
}

    public static void main(String[] args) {
        Lessee lessee = new Lessee("我");
        SingleRoomRenter renter_A = new SingleRoomRenter("房东1");
        SingleRoomRenter renter_B = new SingleRoomRenter("房东2");
        ApartmentRenter renter_C = new ApartmentRenter("房东3");

        ConcreteMediator mediator = new ConcreteMediator();
        mediator.register(lessee,renter_A,renter_B,renter_C);

        lessee.send("我需要找套间");
    }

八、迭代器模式

Iterator Pattern,提供一种方法访问一个container对象中各个元素,而又不需暴露该对象的内部细节。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第29张图片

//聚合类的接口,有创建迭代器方法
public interface Food {
    public FoodIterator createIterator();
}

//中餐类---菜名聚合
public class ChineseCuisine implements Food {
    private List<String> list = new ArrayList<>();

    //添加删除元素的方法,这里都考虑了去重,实际使用因事而异可不加
    //顺带一提,需求无重复可用Set而非List,但Set的iterator涉及map,觉得麻烦就用这个了
    public void add(String name) {
        if (!list.contains(name))
            list.add(name);
    }

    public void addAll(String... names) {
        list.addAll(Arrays.asList(names));
        list = list.stream().distinct().collect(Collectors.toList());
    }

    public void remove(String name) {
        list.removeIf(x ->
                x.equals(name)
        );
    }

    @Override
    public ChineseCuisineItreator createIterator() {
        return new ChineseCuisineItreator(list);
    }

    public List<String> getList() {
        return list;
    }
}

//迭代器接口
public interface FoodIterator {
    public String first();

    public boolean hasNext();

    public String currentItem();

    public String next();
}

//中餐的迭代器
public class ChineseCuisineItreator implements FoodIterator {
    private List<String> list;
    private int index = -1;

    public ChineseCuisineItreator(List<String> list) {
        this.list = list;
    }

    public int getIndex() {
        return index;
    }

    @Override
    public String first() {
        index = 0;
        return list.get(0);
    }

    @Override
    public boolean hasNext() {
        return index < list.size() - 1;
    }

    @Override
    public String currentItem() {
        return list.get(index);
    }

    @Override
    public String next() {
        if (hasNext())
            return list.get(++index);
        return null;
    }
}

    public static void main(String[] args) {
        ChineseCuisine aggregate = new ChineseCuisine();
        aggregate.addAll("蒸羊羔","蒸熊掌","蒸鹿尾儿","烧花鸭","烧雏鸡","烧子鹅","卤猪","卤鸭","酱鸡","腊肉","松花","小肚儿");
        ChineseCuisineItreator iterator = aggregate.createIterator();
        while (iterator.hasNext()) {
            System.out.println("第"+(iterator.getIndex()+2)+"道菜,"+iterator.next());
        }
        System.out.println("\n第一个,"+iterator.first());
        System.out.println("\n现在的菜,"+iterator.currentItem());
    }

九、访问者模式

Visitor Pattern,表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。此模式使用了一个访问者类,它改变了元素类的执行算法,元素的执行算法可以随着访问者改变而改变。

涉及访问者模式,经常会提到伪动态双分派概念,这里给予一些介绍:
java原生支持静态分派和动态单分派----静态分派的体现就是方法重载,根据方法入参的类型不同可以执行不同的代码,这是在编译时就可以确定的;而动态单分配指的是执行方法的对象是某一子类对象,而却使用父类的形式调用方法,这在编译时看不出来传入参数,故无法看出来是哪个子类来调用方法,只有在运行时才能看出。
动态双分派----指的是在运行时,根据两个实际类型去判断一个方法的实际运行行为,而访问者模式所实现的伪动态双分派,则是以两次动态单分派来实现动态双分派,因为有方法是两个方法的嵌套,而内外层方法都有子类以父类形式作为参数传入。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第30张图片

//饭店分区---对应图中的Element
public abstract class RestaurantPartition {
    protected String restaurantName;

    public abstract void accept(Vistor vistor);

    public void setRestaurantName(String restaurantName) {
        this.restaurantName = restaurantName;
    }
}

//就餐处--饭店组成部分
public class DinningPlace extends RestaurantPartition {
    private String placeName;

    public DinningPlace(String placeName) {
        this.placeName = placeName;
    }

    @Override
    public void accept(Vistor vistor) {
        vistor.visitDinningPlace(this);
    }

    public String getRestaurantName() {
        return restaurantName;
    }

    public String getPlaceName() {
        return placeName;
    }
}

//柜台--饭店结账处,本例视为只有一个结账柜台
public class Counter extends RestaurantPartition {
    @Override
    public void accept(Vistor vistor) {
        vistor.visitCounter(this);
    }

    public String getRestaurantName() {
        return restaurantName;
    }
}

//饭店---对应图中的Object_Structure
public class Restaurant {
    private String restaurantName;
    private List<RestaurantPartition> list = new ArrayList<>();

    public Restaurant(String restaurantName) {
        this.restaurantName = restaurantName;
    }

    public void add(RestaurantPartition restaurantPartition) {
        restaurantPartition.setRestaurantName(restaurantName);
        list.add(restaurantPartition);
    }

    public void remove(RestaurantPartition restaurantPartition) {
        list.remove(restaurantPartition);
    }

    public void what_happened(Vistor vistor) {
        list.forEach(x -> x.accept(vistor));
    }
}

//访问者
public interface Vistor {
    public void visitDinningPlace(DinningPlace dinningPlace);

    public void visitCounter(Counter counter);
}

//顾客--访问者的实现
public class Customer implements Vistor {
    private String name;

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

    @Override
    public void visitDinningPlace(DinningPlace dinningPlace) {
        System.out.println("顾客" + name + "在" + dinningPlace.getRestaurantName() + "的" + dinningPlace.getPlaceName() + "就餐");
    }

    @Override
    public void visitCounter(Counter counter) {
        System.out.println("顾客" + name + "到" + counter.getRestaurantName() + "的柜台结账");
    }
}

//员工--访问者的实现
public class Worker implements Vistor{
    private String name;

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

    @Override
    public void visitDinningPlace(DinningPlace dinningPlace) {
        System.out.println("员工"+name+"到"+dinningPlace.getRestaurantName()+"的"+dinningPlace.getPlaceName()+"上菜");
    }

    @Override
    public void visitCounter(Counter counter) {
        System.out.println("员工"+name+"到"+counter.getRestaurantName()+"的柜台处理结账");
    }
}

    public static void main(String[] args) {
        Restaurant restaurant = new Restaurant("醉梦楼");
        DinningPlace dinningPlace = new DinningPlace("天字第一号包厢");
        Counter counter = new Counter();
        restaurant.add(dinningPlace);
        restaurant.add(counter);

        Customer customer = new Customer("张三");
        Worker worker = new Worker("甲");

        restaurant.what_happened(customer);
        System.out.println();
        restaurant.what_happened(worker);
    }

十、备忘录模式

Memento Pattern,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。此模式会保存一个对象的某个状态,以便在适当的时候恢复对象。

在这里插入图片描述

//发起者,负责创建备忘录,并且可以记录、恢复自身的内部状态
public class Originator {
    private String state;

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

    public String getState() {
        return state;
    }

    public Memento saveStateToMemento() {
        return new Memento(state);
    }

    public void getStateFromMemento(Memento Memento) {
        state = Memento.getState();
    }
}

//备忘录,用于存储Originator的状态,并限定只由Originator访问Memento
public class Memento {
    private String state;

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

    public String getState() {
        return state;
    }
}

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

    public void add(Memento state) {
        mementoList.add(state);
    }

    public Memento get(int index) {
        return mementoList.get(index);
    }
}

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

        originator.setState("困倦");
        System.out.println(LocalDateTime.now() +"\t保存当前状态: " + originator.getState());
        careTaker.add(originator.saveStateToMemento());
        originator.setState("清醒");
        System.out.println(LocalDateTime.now() +"\t保存当前状态: " + originator.getState());
        careTaker.add(originator.saveStateToMemento());

        System.out.println();

        originator.setState("兴奋");
        System.out.println(LocalDateTime.now() +"\t当前状态转变为: " + originator.getState());
        originator.getStateFromMemento(careTaker.get(0));
        System.out.println(LocalDateTime.now() +"\t状态恢复至: "  + originator.getState());
        originator.getStateFromMemento(careTaker.get(1));
        System.out.println(LocalDateTime.now() +"\t状态恢复至: " + originator.getState());
    }

十一、解释器模式

Interpreter Pattern,定义语言的文法,并且建立一个解释器来解释该语言中的句子,提供了评估语言的语法或表达式的方式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。
java实现面向对象的23种设计模式【超长预警,读完超过2小时】_第31张图片

//抽象解释器,内含解释方法,可判断传入信息是否符合规则要求
public abstract class Expression {
    public abstract boolean interpret(String info);
}

//终结符表达式,用于判定一个具体量或者一句完整的话是否包含在要求范围内。
//此类对应的,一般有完整的句子、修饰的对象、主语、宾语等,即语义完整。
public class TerminalExpression extends Expression {
    private Set<String> infos = new HashSet<>();

    public TerminalExpression() {
    }

    public TerminalExpression(String info) {
        this.infos.add(info);
    }

    public TerminalExpression(String...infos){
        this.infos.addAll(Arrays.asList(infos));
    }

    @Override
    public boolean interpret(String info) {
        if(infos.contains(info)){
            return true;
        }
        return false;
    }
}

//非终结符表达式,用于判定表达式结合组成的新表达式是否符合规则。
//NonterminalExpression,一般对应连接终端表达式的符号,比如or、and、+、-等。
// 本例使用的是and,即两个表达式均通过规则才算通过。
public class AndExpression extends Expression {
    private Expression place;
    private Expression pet;

    public AndExpression(Expression place, Expression pet) {
        this.place = place;
        this.pet = pet;
    }

    @Override
    public boolean interpret(String info) {
        String[] message = info.split("养");
        return place.interpret(message[0]) && pet.interpret(message[1]);
    }
}

//组合形成的上下文类Context
//定义规则,小区A、B、C允许养猫、狗,其它视为不确定。
public class AllowPet {
    private TerminalExpression placeExpression = new TerminalExpression("小区A", "小区B", "小区C");
    private TerminalExpression petExpression = new TerminalExpression("猫", "狗");
    private AndExpression resultExpression = new AndExpression(placeExpression,petExpression);

    public void allow_or_not(String place, String pet) {
        if (resultExpression.interpret(place + "养" + pet)) {
            System.out.println(place+"允许养"+pet);
        } else {
            System.out.println(place+"不知是否允许养"+pet);
        }
    }
}

    public static void main(String[] args) {
        AllowPet allowPet = new AllowPet();
        allowPet.allow_or_not("小区A", "狗");
        allowPet.allow_or_not("小区B", "鲸鱼");
    }

你可能感兴趣的:(操作,java,设计模式,面向对象编程,程序设计,其他)