23种设计模式的学习

什么是设计模式

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。简单说:模式:在某些场景下,针对某类问题的某种通用的解决方案。场景:项目所在的环境问题:约束条件,项目目标等解决方案:通用、可复用的设计,解决约束达到目标。

面向对象7大设计原则详解

设计原则 设计原则定义 设计原则详解
开闭原则 开闭原则是指一个软件实体,如类、模块和函数应该对扩展开放,对修改关闭,也就是说一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。 https://geek-docs.com/design-pattern/design-principle/open-close-principle.html
里氏替换原则 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法 https://geek-docs.com/design-pattern/design-principle/liskov-substitution-principle.html
迪米特原则 迪米特原则目的是尽量降低类与类之间的耦合。陌生的类最好不要作为局部变量的形式出现在类的内部。 https://geek-docs.com/design-pattern/design-principle/law-of-demeter.html
单一职责原则 单一职责原则(Single Responsibility Principle)是面向对象设计原则的一种。单一职责原则是指不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。 https://geek-docs.com/design-pattern/design-principle/single-responsibility-principle.html
接口分离原则 接口分离原则指在设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。 https://geek-docs.com/design-pattern/design-principle/interface-segregation-principle.html
依赖倒置原则 依赖倒置原则指的是高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定)。抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)。 https://geek-docs.com/design-pattern/design-principle/dependence-inversion-principle.html
组合/聚合复用原则 组合/聚合复用原则是指尽量使用组合/聚合,不要使用类继承。 https://geek-docs.com/design-pattern/design-principle/composite-aggregate-reuse-principle.html

设计模式的三个分类

创建型模式:对象实例化的模式,创建型模式用于解耦对象的实例化过程。结构型模式:把类或对象结合在一起形成一个更大的结构。行为型模式:类和对象如何交互,及划分责任和算法。

各分类中模式的关键点

创建型模式

单例模式:某个类只能有一个实例,提供一个全局的访问点。简单工厂:一个工厂类根据传入的参量决定创建出那一种产品类的实例。工厂方法:定义一个创建对象的接口,让子类决定实例化那个类。抽象工厂:创建相关或依赖对象的家族,而无需明确指定具体类。建造者模式:封装一个复杂对象的构建过程,并可以按步骤构造。原型模式:通过复制现有的实例来创建新的实例。

结构性模式

适配器模式:将一个类的方法接口转换成客户希望的另外一个接口。组合模式:将对象组合成树形结构以表示“”部分-整体“”的层次结构。装饰模式:动态的给对象添加新的功能。代理模式:为其他对象提供一个代理以便控制这个对象的访问。亨元(蝇量)模式:通过共享技术来有效的支持大量细粒度的对象。外观模式:对外提供一个统一的方法,来访问子系统中的一群接口。桥接模式:将抽象部分和它的实现部分分离,使它们都可以独立的变化。

行为型模式

模板模式:定义一个算法结构,而将一些步骤延迟到子类实现。解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器。策略模式:定义一系列算法,把他们封装起来,并且使它们可以相互替换。状态模式:允许一个对象在其对象内部状态改变时改变它的行为。观察者模式:对象间的一对多的依赖关系。备忘录模式:在不破坏封装的前提下,保持对象的内部状态。中介者模式:用一个中介对象来封装一系列的对象交互。命令模式:将命令请求封装为一个对象,使得可以用不同的请求来进行参数化。访问者模式:在不改变数据结构的前提下,增加作用于一组对象元素的新功能。责任链模式:将请求的发送者和接收者解耦,使的多个对象都有处理这个请求的机会。迭代器模式:一种遍历访问聚合对象中各个元素的方法,不暴露该对象的内部结构。

23种设计模式详解

设计模式 定义 设计模式详解
抽象工厂模式 抽象工厂模式(Abstract Factory Pattern)提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。 https://geek-docs.com/design-pattern/abstract-factory
工厂方法模式 工厂方法模式是简单工厂模式的进一步抽象和推广,是GoF设计模式的一种。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。 https://geek-docs.com/design-pattern/factory-method
建造者模式 建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 https://geek-docs.com/design-pattern/builder-pattern
原型模式 原型模式(Prototype Pattern)是一种创建型设计模式,使你能够复制已有对象,而又无需使代码依赖它们所属的类。 https://geek-docs.com/design-pattern/prototype-pattern
单例模式 单例模式(Singleton Pattern)是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。 https://geek-docs.com/design-pattern/singleton-pattern
适配器模式 适配器模式(Adapter Pattern) 是一种结构型设计模式, 它能使接口不兼容的对象能够相互合作。 https://geek-docs.com/design-pattern/adapter-pattern
桥接模式 桥接模式(Bridge Pattern)是一种结构型设计模式, 可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构, 从而能在开发时分别使用。 https://geek-docs.com/design-pattern/bridge-pattern
组合模式 组合模式(Composite Pattern)是一种结构型设计模式, 你可以使用它将对象组合成树状结构,并且能像使用独立对象一样使用它们。 https://geek-docs.com/design-pattern/composite-pattern
装饰者模式 装饰者模式(Decorator Pattern) 是一种结构型设计模式, 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。 https://geek-docs.com/design-pattern/decorator-pattern
外观模式 外观模式(Facade Pattern)是一种结构型设计模式, 能为程序库、 框架或其他复杂类提供一个简单的接口。 https://geek-docs.com/design-pattern/facade-pattern
享元模式 是一种结构型设计模式, 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象。 https://geek-docs.com/design-pattern/flyweight-pattern
代理模式 是一种结构型设计模式, 让你能够提供对象的替代品或其占位符。 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。 https://geek-docs.com/design-pattern/proxy-pattern
责任链模式 是一种行为型设计模式。允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。 https://geek-docs.com/design-pattern/chain-of-responsibility
命令模式 是一种行为设计模式, 它可将请求转换为一个包含与请求相关的所有信息的独立对象。 https://geek-docs.com/design-pattern/command-pattern
迭代器模式 是一种行为设计模式, 让你能在不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素。 https://geek-docs.com/design-pattern/iterator-pattern
中介者模式 是一种行为设计模式, 能让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作。 https://geek-docs.com/design-pattern/mediator-pattern
备忘录模式 是一种行为设计模式, 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。 https://geek-docs.com/design-pattern/memento-pattern
观察者模式 是一种行为设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。 https://geek-docs.com/design-pattern/observer-pattern
状态模式 是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 https://geek-docs.com/design-pattern/state-pattern
策略模式 是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。 https://geek-docs.com/design-pattern/strategy-pattern
模板方法模式 是一种行为设计模式, 它在超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 https://geek-docs.com/design-pattern/template-method-pattern
访问者模式 是一种行为型设计模式, 访问者模式能将算法与其所作用的对象隔离开来。 https://geek-docs.com/design-pattern/visitor-pattern

工厂模式

一个类的创建不用关心内部是怎么实现的,直接使用工厂获取即可

分类

  • 简单工厂模式
  • 普通工厂模式
  • 抽象工厂模式

简单工厂模式

优点

帮助封装
简单工厂虽然很简单,但是非常友好地帮助我们实现了组件的封装,然后让组件外部能真正面向接口编程。解耦通过简单工厂,实现了客户端和具体实现类的解耦。

缺点

可能增加客户端的复杂度如果通过客户端的参数来选择具体的实现类,那么就必须让客户端能理解各个参数所代表的具体功能和含义,这样会增加客户端使用的难度,也部分暴露了内部实现,这种情况可以选用可配置的方式来实现。不方便扩展子工厂私有化简单工厂的构造方法,使用静态方法来创建接口,也就不能通过写简单工厂类的子类来改变创建接口的方法的行为了。不过,通常情况下是不需要为简单工厂创建子类的。

car

public interface Car {void  name();
}

qq

public class QqCar implements Car {public void name() {System.out.println("qq汽车");}
}

wulin

public class WulinCar implements Car {public void name() {System.out.println("五菱宏观");}
}

factory

//简单工厂
public class CarFactory {public Car getCar(String name){if("五菱宏光".equals(name)){return new WulinCar();}else if("qq汽车".equals(name)){return new QqCar();}return null;}//一个对象一个方法public Car getWulin(){return new WulinCar();}}

consumer

public class Consumer {public static void main(String[] args) {CarFactory carFactory = new CarFactory();Car qq = carFactory.getCar("qq汽车");Car wulin = carFactory.getCar("五菱宏光");Car wulin1 = carFactory.getWulin();qq.name();wulin.name();wulin1.name();}
}

普通工厂模式

优点

和简单方法类似,对比简单方法拓展性更强

缺点

当产品的品类多时,所需要的接口就会越来越多,每个产品创建时都需要该品类相对应的属性,一个对象一个接口,增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
例如:创建qq汽车,需要传递参数,qq汽车的轮胎,框架,喷漆等等,每一个都是一个接口,增加系统的复杂程度由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

OrdinaryFactroy

public interface OrdinaryFactory {Car getCar();
}

wulinFactory

public class WulinFactory implements OrdinaryFactory {public Car getCar() {return new WulinCar();}
}

QqFactory

public class QqFactory implements OrdinaryFactory {public Car getCar() {return new QqCar();}
}

consumer

public class Consumer {public static void main(String[] args) {OrdinaryFactory wulinFactory = new WulinFactory();OrdinaryFactory QqFactroy = new QqFactory();Car wulin = wulinFactory.getCar();Car qq = QqFactroy.getCar();wulin.name();qq.name();}
}

抽象工厂模式

优点

生产统一系的产品,可以确保同一工厂生成的产品相互匹配
单一职责原则。 你可以将产品生成代码抽取到同一位置, 使得代码易于维护。
开闭原则。 向应用程序中引入新产品变体时, 你无需修改客户端代码。

缺点

由于采用该模式需要向应用中引入众多接口和类, 代码可能会比之前更加复杂。

车零件工厂案例

//抽象工厂
public interface AbstractFactroy {CarGlass getCarGlass();Frame getFrame();Tire getTire();
}
//车玻璃
public interface CarGlass {void name();
}public class qqGlass implements CarGlass {public void name() {System.out.println("qq汽车的玻璃");}
}
//车架
public interface Frame {void name();
}public class QqFrame implements Frame {public void name() {System.out.println("qq汽车的框架");}
}
//轮胎
public interface Tire {void name();
}public class QqTire implements Tire {public void name() {System.out.println("qq汽车的轮胎");}
}

消费者

public class Consumer {public static void main(String[] args) {QqFactory qqFactory = new QqFactory();CarGlass carGlass = qqFactory.getCarGlass();Frame frame = qqFactory.getFrame();Tire tire = qqFactory.getTire();carGlass.name();frame.name();tire.name();}
}

单例模式

能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。

分类

  • DCL懒汉式
  • 饿汉式
  • 静态内部类
  • 枚举类

饿汉式

public class Teacher {//私有化构造器private Teacher(){}private final static Teacher TEACHER = new Teacher();public static Teacher getInstance(){return  TEACHER;}}//资源提前创建占用了空间,如果不需要使用的话则会造成资源浪费

DCL懒汉式

public class Student {private Student(){}private static volatile   Student STUDENT;public Student getInstance() {if (STUDENT == null) {//提高效率synchronized (Student.class) {if (STUDENT == null) {return new Student();/** 由于new Student();这个过程不是原子性操作,(1.分配内存空间 2.执行构造方法,初始化对象 3.把对象指向这个空间)* 会导致指令重排,所以需要使用volatile* */}}}return STUDENT;}
}

静态内部类

public class Course {private Course(){}public  static Course getInstance(){return innerClass.course;}public  static class innerClass{private static final Course course = new Course();}
}

由于反射机制所以以上方法均可以被反射机制所破坏

public class Consumer {public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {//饿汉式Teacher teacher = Teacher.getInstance();Class<? extends Teacher> teacherClass = teacher.getClass();Constructor<? extends Teacher> teacherConstructor = teacherClass.getDeclaredConstructor();teacherConstructor.setAccessible(true);Teacher newInstance = teacherConstructor.newInstance(null);System.out.println(teacher);System.out.println(newInstance);}
}输出:mybatis.demo.one.design.single.Teacher@45ee12a7mybatis.demo.one.design.single.Teacher@330bedb4   

反射的newInstance方法

 if ((clazz.getModifiers() & Modifier.ENUM) != 0)throw new IllegalArgumentException("Cannot reflectively create enum objects");ConstructorAccessor ca = constructorAccessor;   // read volatileif (ca == null) {ca = acquireConstructorAccessor();}@SuppressWarnings("unchecked")T inst = (T) ca.newInstance(initargs);return inst;}所以如果对象类型是枚举类,则无法创建实例

建造者模式

优缺点

建造者模式优点你可以分步创建对象, 暂缓创建步骤或递归运行创建步骤。生成不同形式的产品时, 你可以复用相同的制造代码。单一职责原则。 你可以将复杂构造代码从产品的业务逻辑中分离出来。
建造者模式缺点由于该模式需要新增多个类, 因此代码整体复杂程度会有所增加。

实现方法

清晰地定义通用步骤, 确保它们可以制造所有形式的产品。 否则你将无法进一步实施该模式。
在基本生成器接口中声明这些步骤。为每个形式的产品创建具体生成器类, 并实现其构造步骤。不要忘记实现获取构造结果对象的方法。 你不能在生成器接口中声明该方法, 因为不同生成器构造的产品可能没有公共接口, 因此你就不知道该方法返回的对象类型。 但是, 如果所有产品都位于单一类层次中, 你就可以安全地在基本接口中添加获取生成对象的方法。考虑创建主管类。 它可以使用同一生成器对象来封装多种构造产品的方式。客户端代码会同时创建生成器和主管对象。 构造开始前, 客户端必须将生成器对象传递给主管对象。 通常情况下, 客户端只需调用主管类构造函数一次即可。 主管类使用生成器对象完成后续所有制造任务。 还有另一种方式, 那就是客户端可以将生成器对象直接传递给主管类的制造方法。只有在所有产品都遵循相同接口的情况下, 构造结果可以直接通过主管类获取。 否则, 客户端应当通过生成器获取构造结果。

接口类

public interface Build {Hourse reset();void setDoor();void setWindow();void setLawn();Hourse build();
}public interface Door {public void name();}public interface Lawn {public void name();
}public interface Window {public void name();
}

实现类

public class ChinaDoor implements Door{public void name() {System.out.println("中国风的门");}
}public class ChinaLawn implements Lawn {public void name() {System.out.println("中国风的草坪");}
}public class ChinaWindow implements Window {public void name() {System.out.println("中国风的窗子");}
}//构造者实现类public class ChineseStyleBuild implements Build {public Hourse hourse;public ChineseStyleBuild(){this.hourse =   this.reset();}public Hourse reset() {return new Hourse();}public void setDoor() {hourse.setDoor(new ChinaDoor());}public void setWindow() {hourse.setWindow(new ChinaWindow());}public void setLawn() {hourse.setLawn(new ChinaLawn());}public Hourse build() {Hourse hourse1 = this.hourse;this.reset();return hourse1;}
}//主管类
public class Director {public Build chineseStyleBuild;public Director(Build chineseStyleBuild){this.chineseStyleBuild = chineseStyleBuild;}public void build(){chineseStyleBuild.setDoor();chineseStyleBuild.setLawn();chineseStyleBuild.setWindow();}}

测试

public class Consumer {public static void main(String[] args) {ChineseStyleBuild chineseStyleBuild = new ChineseStyleBuild();Director director = new Director(chineseStyleBuild);director.build();Hourse build = chineseStyleBuild.build();System.out.println(build);}
}

原型模式

场景

如果你需要复制一些对象, 同时又希望代码独立于这些对象所属的具体类, 可以使用原型模式。如果子类的区别仅在于其对象的初始化方式, 那么你可以使用该模式来减少子类的数量。 别人创建这些子类的目的可能是为了创建特定类型的对象。

优缺点

原型模式优点你可以克隆对象, 而无需与它们所属的具体类相耦合。你可以克隆预生成原型, 避免反复运行初始化代码。你可以更方便地生成复杂对象。你可以用继承以外的方式来处理复杂对象的不同配置。原型模式缺点克隆包含循环引用的复杂对象可能会非常麻烦。

深复制与浅复制

浅复制:Java中的浅复制是通过实现Cloneable接口并重写clone方法实现。在浅复制的过程中,对象的基本数据类型的变量值会重新被复制和创建,而引用数据类型仍指向原对象的引用,也就是说浅复制不复制对象的引用数据类型;深复制:在深复制的过程中,不论是基本数据类型还是引用数据类型,都会被重新复制和创建。简而言之,深复制彻底复制了对象的数据,浅复制的复制不彻底(忽略了引用数据类型)。

浅复制

public class Computer implements Cloneable {private String cpu;private String memory;private String disk;public Computer(String cpu, String memory, String disk) {this.cpu = cpu;this.memory = memory;this.disk = disk;}@Overridepublic String toString() {return "Computer{" +"cpu='" + cpu + '\'' +", memory='" + memory + '\'' +", disk='" + disk + '\'' +'}';}@Overridepublic Object clone(){try {return (Computer) super.clone();}catch (Exception e){e.printStackTrace();return null;}}
}

深复制

public class ComputerDetail implements Cloneable {private String cpu;private String memory;private Disk disk;public ComputerDetail(String cpu, String memory, Disk disk) {this.cpu = cpu;this.memory = memory;this.disk = disk;}@Overridepublic String toString() {return "ComputerDetail{" +"cpu='" + cpu + '\'' +", memory='" + memory + '\'' +", disk=" + disk +'}';}@Overridepublic Object clone(){try {ComputerDetail computerDetail= (ComputerDetail) super.clone();computerDetail.disk= (Disk) this.disk.clone();return computerDetail;}catch (Exception e){e.printStackTrace();return null;}}
}class Disk implements Cloneable{private String ssd;private String hhd;public Disk(String ssd, String hhd) {this.ssd = ssd;this.hhd = hhd;}@Overridepublic String toString() {return "Disk{" +"ssd='" + ssd + '\'' +", hhd='" + hhd + '\'' +'}';}@Overridepublic Object clone(){try{return super.clone();}catch (Exception e){e.printStackTrace();return null;}}
}

适配器模式

适配器模式通过定义一个适配器类作为两个不兼容的接口之间的桥梁,将一个类的接口转换成用户期望的另一个接口,使得两个或多个原本不兼容的接口可以基于适配器类一起工作。

分类

在适配器模式的实现中有三种角色:source、targetable、adapter。sourc是待适配的类,targetable是目标接口,adapter是适配器。我们在具体应用中通过adapter将source的功能扩展到targetable适配器的实现主要分为三类:类适配器模式、对象适配器模式、接口适配器模式。

类适配器模式

待适配的Source类

public class Source {public void editText(){System.out.println("编辑text文件");}
}

targetable目标接口

public interface Targetable {void editText();void editWord();
}

adapter适配器

	public class Adapter extends Source implements Targetable{@Overridepublic void editWord() {System.out.println("编辑word文件");}
}

使用

public static void main(String[] args) {Targetable targetable=new Adapter();targetable.editText();targetable.editWord();}

对象适配器模式

对象适配器模式的思路和类适配器模式基本相同,只是修改了Adapter类。Adapter不再继承Source类,而是持有Source类的实例以解决兼容性问题。

adapter适配器

public class ObjectAdapter implements Targetable {private Source source;public ObjectAdapter(Source source){this.source=source;}@Overridepublic void editText() {this.source.editText();    }@Overridepublic void editWord() {System.out.println("编辑word文件");}
}

使用

public static void main(String[] args) {Source source=new Source();Targetable targetable=new ObjectAdapter(source);targetable.editText();targetable.editWord();}

接口适配器模式

在不希望实现一个接口中的所有方法时,可以创建一个抽象类AbstractAdapter实现所有方法,在使用时继承该抽象类按需实现方法即可。

Sourceable

public interface Sourceable {void editText();void editWord();
}

抽象类AbstarctAdapter

public class AbstarctAdapter implements Sourceable {@Overridepublic void editText() {}@Overridepublic void editWord() {}
}

定义SourceSub1按照需求实现editText()

public class SourceSub1 extends AbstarctAdapter {@Overridepublic void editText() {System.out.println("编辑text文件");}
}

定义SourceSub2按照需求实现editWord()

public class SourceSub2 extends AbstarctAdapter {@Overridepublic void editWord() {System.out.println("编辑word文件");}
}

使用

public static void main(String[] args) {Sourceable source1=new SourceSub1();Sourceable source2=new SourceSub2();source1.editText();source2.editWord();}

装饰者模式

装饰者模式指在无需改变原有类及类的继承关系的情况下,动态扩展一个类的功能。它通过装饰者来包裹真实的对象,并动态地向对象添加或者撤销功能。

定义Sourceable接口

public interface Sourceable {public void createWife();
}

实现类

public class Source implements Sourceable {@Overridepublic void createWife() {System.out.println("create wife by Source");}
}

装饰者类

public class Decorartor implements Sourceable {private Sourceable source;public Decorartor(Sourceable source){this.source=source;}@Overridepublic void createWife() {source.createWife();System.out.println("your wife becomes 36D");}
}

使用

public static void main(String[] args) {Sourceable source=new Source();Decorartor decorartor = new Decorartor(source);decorartor.createWife();}

代理模式

代理模式指为对象提供一种通过代理的方式来访问并控制该对象行为的方法。在客户端不适合或者不能够直接引用一个对象时,可以通过该对象的代理对象实现对该对象的访问,可以将该代理对象理解为客户端和目标对象之间的中介者

定义Company接口及其实现类Hr:

public interface Company {void findWorker(String title);
}public class Hr implements Company {@Overridepublic void findWorker(String title) {System.out.println("我需要找招聘一个员工,岗位是:"+title);}
}

定义代理类

public class Proxy implements Company {private Hr hr;public Proxy(){this.hr=new Hr();}@Overridepublic void findWorker(String title) {hr.findWorker(title);System.out.println("找到了员工:"+getWorker(title));}private String getWorker(String title){Map<String,String> workerList=new HashMap<String,String>(){{put("Java","james");put("Python","kobe");}};return workerList.get(title);}
}

测试

 public static void main(String[] args) {Company company=new Proxy();company.findWorker("Java");}

外观模式

外观模式也叫做门面模式,通过一个门面向客户端提供一个访问系统的统一接口,客户端无需关心和知晓系统内部各子模块(系统)之间的复杂关系,其主要目的是降低访问拥有多个子系统的复杂系统的难度,简化客户端与其之间的接口。外观模式将子系统中的功能抽象成一个统一的接口,客户端通过这个接口访问系统,使得系统使用起来更加容易。

找老婆为例,你只想找一个好看的,学历好的老婆,并不会关注她是不是人工的,毕业证是怎么拿的。

public class MakeFace {public void start(){System.out.println("your wife is ugly");}public void end(){System.out.println("your wife is beautiful now!");}
}
public class MakeStudy {public void start(){System.out.println("your wife is fool");}public void end(){System.out.println("your wife is clever now!");}
}
public class MakeWife {private MakeFace makeFace;private MakeStudy makeStudy;public MakeWife() {this.makeFace = new MakeFace();this.makeStudy = new MakeStudy();}public void start(){makeFace.start();makeStudy.start();}public void end(){makeFace.end();makeStudy.end();}
}

使用

public static void main(String[] args) {MakeWife makeWife = new MakeWife();makeWife.start();makeWife.end();}

桥接模式

桥接模式通过将抽象及其实现解耦,使二者可以根据需求独立变化。这种类型的设计模式属于结构型模式,通过定义一个抽象和实现之间的桥接者来达到解耦的目的。桥接模型主要用于解决在需求多变的情况下使用继承造成类爆炸的问题,扩展起来不够灵活。如:包类,属性有性别,颜色,款式。每个属性都有多个值,每个值都能进行两两组合成新的类(男士黑色皮包类,女式黑色皮包类,男士红色皮包类...),如果要进行拓展会造成类的指数性增长,形成类爆炸。解决:对不断变化的属性进行抽象,当需要新增某个属性值时只需要实现它,然后将实现类传入一个封装了该实现类的抽象类的实现

JDBC和DriverManager就使用了桥接模式,JDBC在连接数据库时,在各个数据库之间切换而不需要修改代码,因为JDBC提供了统一的接口,每个数据库都提供了各自的实现

定义Driver接口

public interface Driver {void executeSql();
}

定义MySQL的实现类

public class MysqlDriver implements Driver {@Overridepublic void executeSql() {System.out.println("使用mysql执行sql");}
}

定义Oracle的实现类

public class OracleDriver implements Driver {@Overridepublic void executeSql() {System.out.println("使用oracle执行sql");}
}

定义DriverMangerBridge

public abstract class DriverMangerBridge {private Driver driver;public void execute(){driver.executeSql();}public Driver getDriver(){return driver;}public void setDriver(Driver driver) {this.driver = driver;}
}

定义MyDriverBridge

public class MyDriverBridge extends DriverMangerBridge {@Overridepublic void execute() {getDriver().executeSql();}
}

使用

 public static void main(String[] args) {DriverMangerBridge driverMangerBridge = new MyDriverBridge();driverMangerBridge.setDriver(new MysqlDriver());driverMangerBridge.execute();driverMangerBridge.setDriver(new OracleDriver());driverMangerBridge.execute();}

组合模式

组合模式又叫做部分整体模式,主要用于实现部分和整体操作的一致性。组合模式常根据树形结构来表示部分及整体之间的关系,使得用户对单个对象和组合对象的操作具有一致性。

定义TreeNode

public class TreeNode {private String name;private TreeNode parent;private Vector<TreeNode> children=new Vector<>();public TreeNode(String name){this.name=name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public TreeNode getParent() {return parent;}public void setParent(TreeNode parent) {this.parent = parent;}public void add(TreeNode node){children.add(node);}public void remove(TreeNode node){children.remove(node);}public Enumeration<TreeNode> getChildren(){return children.elements();}@Overridepublic String toString() {return "TreeNode{" +"name='" + name + '\'' +", parent=" + parent +", children=" + children +'}';}
}

使用

public static void main(String[] args) {TreeNode nodeA=new TreeNode("A");TreeNode nodeB=new TreeNode("B");nodeA.add(nodeB);System.out.println(nodeA);}

享元模式

享元模式主要通过对象的复用减少对象创建的次数和数量,减少系统内存的使用和降低系统负载。享元模式属于结构型模型,在系统需要一个对象时享元模式首先在系统中查找并尝试重用现有的对象,如果未找到匹配对象则创建新对象并将其缓存在系统中。

下面以内存的申请和使用为例介绍享元模式的使用

定义Memory

public class Memory {private int size;private boolean isUsed;private String id;public Memory(int size, boolean isUsed, String id) {this.size = size;this.isUsed = isUsed;this.id = id;}public int getSize() {return size;}public void setSize(int size) {this.size = size;}public boolean isUsed() {return isUsed;}public void setUsed(boolean used) {isUsed = used;}public String getId() {return id;}public void setId(String id) {this.id = id;}
}

定义MemoryFactory工厂

public class MemoryFactory {private static List<Memory> memoryList=new ArrayList<>();public static Memory getMemory(int size){Memory memory=null;for(int i=0;i<memoryList.size();i++){memory=memoryList.get(i);if(memory.getSize()==size&& !memory.isUsed()){memory.setUsed(true);memoryList.set(i,memory);System.out.println("直接获取内存");break;}}if(memory==null){memory=new Memory(32,false, UUID.randomUUID().toString());memoryList.add(memory);System.out.println("创建新内存");}return memory;}public static void releaseMemory(String id){for(int i=0;i<memoryList.size();i++){Memory memory = memoryList.get(i);if(memory.getId().equals(id)){memory.setUsed(false);memoryList.set(i,memory);System.out.println("释放内存");break;}}}
}

使用

public static void main(String[] args) {Memory memory=MemoryFactory.getMemory(32);MemoryFactory.releaseMemory(memory.getId());MemoryFactory.getMemory(32);}

策略模式

 策略模式为同一个行为定义了不同策略,为每种策略实现了不同方法。用户使用时系统根据不同的策略自动切换不同的方法实现策略的改变。同一策略下的不同方法是对同一功能的不同实现,因此在使用时可相互替换而不影响用户的使用。 与桥接模式不同:桥接模式是一个产品的属性有多个值,各种属性值不同会组合成不同的类,所以需要对产品和属性值都进行抽象策略模式:从上下文类中找出修改频率较高的算法,将算法逐一抽取到各自的类中, 它们都必须实现策略接口。在上下文类中添加一个成员变量用于保存对于策略对象的引用。 然后提供设置器以修改该成员变量。 

定义交友策略接口

public interface MakeFriendStrategy {void makeFriendModel();
}

定义该接口的两种实现方式

public class MakeFriendByWx implements MakeFriendStrategy {@Overridepublic void makeFriendModel() {System.out.println("使用微信交友");}
}public class MakeFriendByQq implements MakeFriendStrategy {@Overridepublic void makeFriendModel() {System.out.println("使用qq交友");}
}

定义Context实现策略模式

public class Context {private MakeFriendStrategy makeFriendStrategy;public MakeFriendStrategy getMakeFriendStrategy(){return makeFriendStrategy;}public void setMakeFriendStrategy(MakeFriendStrategy makeFriendStrategy) {this.makeFriendStrategy = makeFriendStrategy;}public void makeFriendMode(){makeFriendStrategy.makeFriendModel();}
}

使用

public static void main(String[] args) {Context context = new Context();context.setMakeFriendStrategy(new MakeFriendByQq());context.makeFriendMode();context.setMakeFriendStrategy(new MakeFriendByWx());context.makeFriendMode();}

模板方法模式

模板方法模式定义了一个算法框架,并通过继承的方式将算法的实现延迟到子类中,使得子类可以在不改变算法框架及其流程的前提下重新定义该算法在某些特定环节的实现,是一种类行为型模式。抽象类:定义算法框架,由基本方法和模板方法组成。基本方法定义了算法有哪些环节,模板方法定义了算法各个环节执行的流程。
具体子类:对在抽象类中定义的算法根据需求进行不同的实现。

定义模板类

public abstract class AbstractTemplate {void templateMethod(){checkNumber();queueUp();handleBusiness();service();}private void checkNumber(){System.out.println("抽号");};private void queueUp(){System.out.println("排队");};public abstract void handleBusiness();private void service(){System.out.println("完成服务");};
}

实现类

public class SaveMoney extends AbstractTemplate {@Overridepublic void handleBusiness() {System.out.println("存钱");}
}public class TakeMoney extends AbstractTemplate {@Overridepublic void handleBusiness() {System.out.println("取钱");}
}

使用模板模式

public static void main(String[] args) {AbstractTemplate template1=new SaveMoney();template1.templateMethod();AbstractTemplate template2=new TakeMoney();template2.templateMethod();}

观察者模式

观察者模式指在被观察者的状态发生变化时,系统基于事件驱动理论将其状态通知到订阅其状态的观察者对象中,以完成状态的修改和事件传播。观察者模式是一种对象行为模式,观察者和被观察者之间的关系属于抽象耦合关系,主要优点是观察者与被观察者之间建立了一套事件触发机制,以降低二者之间的耦合度。观察者模式的主要角色如下:
抽象主题Subject:持有订阅了该主题的观察者对象的集合,同时提供了增加删除观察者对象的方法和主题状态变化后的通知方法
具体主题Concrete Subject:实现了抽象主题的通知方法,在主题内部状态发生变化时,调用该方法通知订阅了主题状态的观察者对象
抽象观察者Observer:观察者的抽象类或接口,定义了主题状态变化时需要调用的方法
具体观察者 Concrete Observer:抽象观察者的实现类,在收到主题状态变化的信息后执行具体触发机制

定义抽象主题Subject

public abstract class Subject {protected List<Observer> observers=new ArrayList<>();public void add(Observer observer){observers.add(observer);}public void remove(Observer observer){observers.remove(observer);}public abstract void notify(String message);
}

定义具体主题ConcreteSubject

public class ConcreteSubject extends Subject {@Overridepublic void notify(String message) {for(Object obj:observers){System.out.println("通知观察者 "+message);((Observer)obj).dataChange(message);}}
}

定义抽象观察者

public interface Observer {void dataChange(String message);
}

定义具体的观察者

public class ConcreteObserver implements Observer {@Overridepublic void dataChange(String message) {System.out.println("收到信息 "+message);}
}

使用‘

public static void main(String[] args) {Subject subject=new ConcreteSubject();Observer obs=new ConcreteObserver();subject.add(obs);subject.notify("lakers win");}

迭代器模式

迭代器模式提供了顺序访问集合对象中的各种元素,而不暴露该对象内部结构的方法。Java中的集合就是典型的迭代器模式,比如HashMap,当遍历HashMap时,需要迭代器不停地获取Next元素就可以循环遍历集合中所有元素。

定义MyCollection集合接口

public interface MyCollection {//对集合元素的迭代Iterator iterator();//取得元素Object get(int i);//添加元素boolean add(Object object);//集合大小int size();
}

接口的实现类MyList

public class MyList implements MyCollection {private List list=new ArrayList();@Overridepublic MyIterator iterator() {return new ConcreteIterator(this);}}@Overridepublic Object get(int i) {return list.get(i);}@Overridepublic boolean add(Object object) {list.add(object);return true;}@Overridepublic int size() {return list.size();}
}

定义迭代器接口MyIterator

public interface MyIterator {//指针前移Object previous();//指针后移Object next();boolean hasNext();
}

迭代器接口实现类ConcreteIterator

public class ConcreteIterator implements MyIterator {private MyCollection myCollection;private int pos=-1;public ConcreteIterator(MyCollection myCollection) {this.myCollection=myCollection;}@Overridepublic Object previous(){if(pos>0)pos--;return myCollection.get(pos);}@Overridepublic Object next() {if(pos<myCollection.size()-1)pos++;return myCollection.get(pos);}@Overridepublic boolean hasNext() {return pos < myCollection.size() - 1;}
}

使用

public static void main(String[] args) {MyCollection myCollection=new MyList();myCollection.add("data1");myCollection.add("data2");MyIterator iterator = myCollection.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}

责任链模式

责任链模式用于避免请求发送者与多个请求处理者耦合在一起,让所有请求的处理者持有下一个对象的引用,从而将请求串联成一条链,在有请求发生时,可将请求沿着这条链传递,直到遇到该对象的处理器。Handler接口规定责任链上要执行的具体方法
AbstractHandler抽象类持有Handler实例并通过get/set方法将各个具体的业务Handler串联成一个责任链,客户端上的请求在责任链上执行
业务Handler用户根据具体的业务需求实现的业务逻辑

定义Handler接口

public interface Handler {void operate();
}

定义AbstractHandler类

public abstract class AbstractHandler {private Handler handler;public Handler getHandler() {return handler;}public void setHandler(Handler handler) {this.handler = handler;}
}

定义用户授权类AuthHandler

public class AuthHandler extends AbstractHandler implements Handler {private String name;public AuthHandler(String name){this.name=name;}@Overridepublic void operate() {System.out.println("用户认证");if(getHandler()!=null){getHandler().operate();}}
}

定义业务处理类BusinessHandler

public class BusinessHandler extends AbstractHandler implements Handler {private String name;public BusinessHandler(String name){this.name=name;}@Overridepublic void operate() {System.out.println("业务调用");if(getHandler()!=null){getHandler().operate();}}
}

定义请求反馈类

public class ResponseHandler extends AbstractHandler implements Handler {private String name;public ResponseHandler(String name){this.name=name;}@Overridepublic void operate() {System.out.println("请求响应");if(getHandler()!=null){getHandler().operate();}}
}

使用

public static void main(String[] args) {AuthHandler authHandler=new AuthHandler("auth");BusinessHandler businessHandler=new BusinessHandler("buss");ResponseHandler responseHandler=new ResponseHandler("res");authHandler.setHandler(businessHandler);businessHandler.setHandler(responseHandler);authHandler.operate();//会先执行自己的任务,任何执行类中字段的任务}

命令模式

命令模式将请求封装为命令基于事件驱动异步执行,以实现命令的发送者和命令的执行者之间的解耦,提高命令发送执行的效率和灵活度。抽象命令类执行命令的接口,定义执行命令的抽象方法
具体命令类抽象命令类的实现类,持有接收者对象,并在收到命令后调用命令执行者的方法action()实现命令的调用和执行
命令执行者命令的具体执行者,定义了命令执行的具体方法action()
命令调用者接收客户端的命令并异步执行

定义Command接口

public interface Command {public void execute(String command);
}

定义具体命令类ConcreteCommand

public class ConcreteCommand implements Command {private Receiver receiver;public ConcreteCommand(Receiver receiver){this.receiver=receiver;}@Overridepublic void execute(String command) {receiver.action(command);    }
}

定义命令的接收者和执行者Receiver

public class Receiver {public void action(String command){System.out.println("接收命令,开始执行"+command);}
}

定义命令调用者类Invoker

public class Invoker {private Command command;public Invoker(Command command){this.command=command;}public void action(String command){System.out.println("发送命令");this.command.execute(command);}
}

使用

public static void main(String[] args) {Command command=new ConcreteCommand(new Receiver());Invoker invoker=new Invoker(command);invoker.action("exe the command");}

使用命令模式时要定义一个命令接收和执行者Receiver,接着定义一个具体的命令实例,并将命令接收者实例设置到命令实例中,然后定义一个命令调用者Invoker实例,将命令实例设置到执行者中,最后调用命令调用者的action方法,发送命令,在命令接收者收到数据后会执行相关命令,这样就完成了命令的调用。

备忘录模式

备忘录模式又叫做快照模式,该模式将当前对象的内部状态保存到备忘录中,以便在需要时能将对象的状态恢复到原先保存的状态。发起人Originator记录当前时刻的内部状态,定义创建备忘录和回复备忘录数据的方法
备忘录Memento负责存储对象的内部状态
状态管理者Storage对备忘录的历史状态进行存储,定义了保存和获取备忘录状态的功能。注意备忘录只能被保存或恢复,不能进行修改。

定义原始数据Original

public class Original {private String value;public String getValue() {return value;}public void setValue(String value) {this.value = value;}public Memento createMemento(){//创建备忘录return new Memento(value);}public void restoreMemento(Memento memento){//恢复数据this.value=memento.getValue();}
}

定义备忘录Memento

public class Memento {private String value;public Memento(String value){this.value=value;}public String getValue() {return value;}public void setValue(String value) {this.value = value;}
}

定义备忘录管理者Storage

public class Storage {private Memento memento;public Storage(Memento memento){this.memento=memento;}public Memento getMemento() {return memento;}public void setMemento(Memento memento) {this.memento = memento;}
}

使用

public static void main(String[] args) {//创建原始类Original original=new Original("original data");//创建备忘录Storage storage=new Storage(original.createMemento());//修改原始类数据System.out.println("原始数据:"+original.getValue());original.setValue("new data");System.out.println("当前数据 "+original.getValue());//恢复数据original.restoreMemento(storage.getMemento());System.out.println("恢复数据为 "+original.getValue());}

备忘录的使用方法比较简单,先定义一个原始数据,然后将数据存到Storage,这时可以修改数据,在我们想把数据恢复时,调用原始类的restoreMemento方法即可

状态模式 State

状态模式指给对象定义不同的状态,并为不同的状态定义不同的行为,在对象的状态发生变换时自动切换状态的行为。状态模式是一种对象行为型模式,它将对象的不同行为封装到不同的状态中,遵循单一职责原则。(1)环境: 也叫做上下文,用于维护对象当前的状态,并在对象状态发生变化时触发对象行为的变化
(2)抽象状态:定义接口,用于定义对象中不同状态对应行为
(3)具体状态:抽象状态的实现类

定义AbstractState

public abstract class AbstractState {public abstract void action(Context context);
}

定义AbstractState的子类HolidayState

public class HolidayState extends AbstractState {@Overridepublic void action(Context context) {System.out.println("切换到假期状态");}
}

定义AbstractState的子类WorkState

public class WorkState extends AbstractState {@Overridepublic void action(Context context) {System.out.println("切换到工作状态");}
}

定义Context存储状态和执行不同状态下行为

public class Context {private AbstractState state;public Context(AbstractState state){this.state=state;}public void setState(AbstractState state) {this.state = state;}public AbstractState getState() {return state;}public void action(){state.action(this);}
}

使用

public static void main(String[] args) {Context context = new Context(new HolidayState());context.action();context.setState(new WorkState());context.action();}

使用状态模式时,只需定义一个上下文Context,并设置Context中的状态,然后调用行为方法即可。

访问者模式

访问者模式指将数据结构和数据的操作分离开来,使其在不改变数据结构的前提下动态添加作用于这些元素的操作。访问者模式通过定义不同的访问者实现对数据的不同操作,因此在需要给数据添加新的操作时只需为其定义一个新的访问者即可。抽象访问者定义了一个访问元素的接口,为每类元素都定义了一个访问操作,该操作中的参数类型对应被访问元素的数据类型
具体访问者抽象访问者的实现类,实现了不同访问者访问元素后具体行为
抽象元素定义了访问该元素的入口方法,不同访问者类型代表不同访问者
具体元素实现抽象元素定义的入口方法,根据访问者的不同类型实现不同逻辑业务

定义抽象接口Vistor

public interface Vistor {void visit(ProjectElement element);
}

定义Vistor实现类Manager

public class Manager implements Vistor {@Overridepublic void visit(ProjectElement element) {System.out.println("管理员审核项目");element.signature("manager",new Date());}
}

定义Vistor实现类Ceo

public class Ceo implements Vistor {@Overridepublic void visit(ProjectElement element) {System.out.println("CEO审核项目");element.signature("ceo",new Date());}
}

定义抽象元素Element

public interface Element {void accept(Vistor vistor);
}

定义具体元素ProjectElement

public class ProjectElement implements Element {private String name;private String vistor;private Date date;public ProjectElement(String name) {this.name = name;}@Overridepublic void accept(Vistor vistor) {vistor.visit(this);}public void signature(String vistor,Date time){this.vistor=vistor;this.date=time;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getVistor() {return vistor;}public void setVistor(String vistor) {this.vistor = vistor;}public Date getDate() {return date;}public void setDate(Date date) {this.date = date;}
}

使用

public static void main(String[] args) {Element element=new ProjectElement("java");element.accept(new Manager());element.accept(new Ceo());}

中介者模式

 中介者模式指对象和对象之间不直接交互,而是通过一个名为中介者的角色来实现,使原有对象之间的关系变得松散,且可以通过定义不同的中介者来改变它们之间的交互。主要包含以下角色: 抽象中介者中介者接口,定义了注册同事对象方法和转发同时对象信息的方法
具体中介者中介者接口的实现类,定义了一个集合保存同事对象,协调各同事角色之间的交互关系
抽象同事类定义同事的接口类,持有中介者对象,并定义同事对象交互的抽象方法,同时实现同事类的公共方法和功能
具体同事类抽象同事的实现类,在需要与其他同事对象交互时,通过中介者对象来完成

定义抽象的Colleague类

public abstract class Colleague {protected Mediator mediator;public void setMediator(Mediator mediator) {this.mediator = mediator;}//同事类的操作public abstract boolean operation(String message);
}

定义具体的房东类

public class ColleagueLandord extends Colleague {@Overridepublic boolean operation(String message) {System.out.println("房东收到中介的消息:"+message);return true;}
}

定义具体的租户类

public class ColleagueTenant extends Colleague {@Overridepublic boolean operation(String message) {System.out.println("租客收到中介的消息:"+message);return true;}
}

定义抽象中介者Mediator

public abstract class Mediator {protected Colleague colleagueTenant;protected Colleague colleagueLandord;public Mediator(Colleague colleagueTenant, Colleague colleagueLandord) {this.colleagueTenant = colleagueTenant;this.colleagueLandord = colleagueLandord;}//通知租客public abstract boolean notifyTenant(String message);//通知房东public abstract boolean notifyLandlord(String message);
}

定义具体的中介

public class ConcreteMediator extends Mediator {public ConcreteMediator(Colleague colleagueTenant, Colleague colleagueLandord) {super(colleagueTenant, colleagueLandord);}@Overridepublic boolean notifyTenant(String message) {if(colleagueTenant!=null)return colleagueTenant.operation(message);return false;}@Overridepublic boolean notifyLandlord(String message) {if(colleagueLandord!=null)return colleagueLandord.operation(message);return false;}
}

使用

public static void main(String[] args) {//定义房客类Colleague tenant=new ColleagueTenant();//定义房东类Colleague landlord=new ColleagueLandord();//创建中介Mediator mediator=new ConcreteMediator(tenant,landlord);boolean result=mediator.notifyTenant("想租房吗?");if(result)mediator.notifyLandlord("想");else mediator.notifyLandlord("不想");}
//使用中介模式时,首先要定义同事类,然后定义中介者并通过中介者完成对象之间的交互。 

解释器模式

https://www.cnblogs.com/adamjwh/p/10938852.html

解释器模式给定一种语言,并定义该语言的语法表示,然后设计一个解释器来解释语言的语法,这种模式常被用于SQL解析、符号处理引擎等。抽象表达式定义解释器的接口,约定解释器所包含的操作
终结符表达式抽象表达式的子类,用来定义语法中和终结符有关的操作,语法中的每一个终结符都应有一个与之对应的终结表达式
非终结符表达式抽象表达式的子类,用来定义语法中和非终结符有关的操作,语法中的每条规则都有一个非终结符表达式与之对应
环境定义各个解释器需要的共享数据或公共功能

定义表达式接口

public interface Expression {//解释方法void interpret(Context context);
}

定义非终结符表达式

 public class NonterminalExpression implements Expression {private Expression left;private Expression right;public NonterminalExpression(Expression left, Expression right) {this.left = left;this.right = right;}@Overridepublic void interpret(Context context) {//递归调用每一个组成部分的interpret}
}

定义终结符表达式

public class TerminalExpression implements Expression {@Overridepublic void interpret(Context context) {//终结符表达式的解释操作}
}

定义Context

public class Context {private HashMap map=new HashMap();public void assign(String key,String val){//在环境类设值}public String get(String key){//获取存储在环境类的值return "";}
}

原文参考: https://blog.csdn.net/qq_41112238/article/details/104752524

https://geek-docs.com/design-pattern