共包含二十三种设计模式,本文将随着笔者的学习逐渐进行完善,下面一起进入主题吧。
设计原则
开闭原则:软件实体对修改关闭,对扩展开发(总纲)
如上生产环境后,新增需求需要修改原先代码逻辑,则破坏了开闭原则。。
单一职责原则:一个类只负责一个功能领域的相应职责 (控制类的粒度大小 )
里氏代换原则:所有引用基类对象的地方都能透明使用其子类的对象 (不要破坏继承体系 )
父类所有公开方法,子类都必须实现,否则调用父类方法时,如果替换为子类会出问题。
父类已实现的方法,子类不可去修改(可super调用后添加自己的逻辑代码)。
依赖倒置原则:抽象不依赖于细节,细节因依赖于抽象 (面向接口编程 )
类的成员变量,方法参数,方法返回值在使用时,能使用抽象层或接口的,不要去依赖具体的实现。
接口隔离原则:使用多个专门的接口,而不是单一的总接口
合成复用原则:尽量使用对象组合,而不是继承达到服用目的 (优先对象组合或聚合关系复用,少用继承 )
迪米特法则:一个软件实体应尽可能少的与其他实体发生相互作用 (降低耦合 )
设计模型类型 创建型(5种):工厂、抽象工厂、单例、原型、构建者
行为型(7种):适配器、装饰、代理、外观、桥接、组合、享元
结构型(11种):模板方法、策略、观察者、中介者、状态、责任链、命令、迭代器、访问者、解释器、备忘录
一、单例模式
什么是单例?
共8种单例写法,展示如下几种
饿汉模式:正如字面意思,即类加载到容器后就会实例化一个单例,JVM保证线程安全
优点:简单实用
缺点:无论用到与否,类加载是就会完成实例化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 /** * @author truly * @date 2023/2/28 24:24 * @Description: 饿汉式 */ public class Singleton { //static修饰的变量在new对象中,不存在多线程问题 private static Singleton singleton=new Singleton(); private Singleton(){ } public static Singleton getInstance(String[] args) { return singleton; } } //jvm通过类加载器加载一个类时是加锁的,也就是线程安全的。类加载时会初始化静态成员,其实就是调用cinit()方法。
较为完美的单例写法:静态内部类的方式
优点:加载外部类的时候不会加载内部类,可以实现懒加载,JVM保证单例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 /** * @author truly * @date 2023/2/28 24:24 * @Description: 懒加载 */ public class Singleton { private Singleton(){ } public static class SingletonHolder{ private final static Singleton INSTANCE=new Singleton();; } public static Singleton getInstance(String[] args) { return SingletonHolder.INSTANCE; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 /** * @author truly * @date 2023/2/28 21:24 * @Description: 懒汉式 */ public class Singleton { private static volatile Singleton singleton; //涉及语句重排序 //第一步将构造函数私有化 private Singleton(){ } //第二步提供获取实例的静态方法 public static Singleton getInstance(String[] args) { if (singleton==null){ synchronized (Singleton.class){ if (singleton==null){ singleton= new Singleton(); } } } return singleton; } }
二、策略模式
什么是策略模式?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 /** * @author truly * @date 2023/2/28 24:24 * @Description: 策略模式实现 */ //作为一个排序的接口 @FunctionalInterface //表明是个函数式接口 public interface Compartor<T> { int compareto(T o1,T o2); default void m(){ System.out.println("JDK1.8后接口可以实现写方法实现!!!"); } } //实现排序接口的具体算法类如下 public class dogCompartor implements Compartor<Dog> { @Override public int compareto(T o1,T o2){ //实现狗排序的具体算法 } } //如果一个比较方法如下 public void sort(T[] arr,Compartor<T> compartor){ //传入一个具体的算法实现,即可使用对应算法 }
三四、工厂模式及抽象工厂模式
什么是工厂模式?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 public interface Moveable{ void go(); } public class Car() implements Moveable{ public void go(){ System.println.out("Car go wuwuwuuwuwwuwu.....") } } /** * @author truly * @date 2023/3/01 24:24 * @Description: 简单工厂模式实现 但可扩展性并不好,违反开闭原则 */ //存在的问题--解决方法 //1.违反开闭原则-------将对象的名称和对象通过配置文件(xml)进行配置,建立映射关系 //2.入参不明确---------将入参设置成要查找对象的类名 //3.实现不方便---------通过对象名称,去map中查找只需要一行代码。spring源码中getBean //可任意定制交通工具---------继承Moveable public class simpleVehicleFactory { public Car createCar(){ retrun new Car(); } public Plane createPlane(){ retrun new Plane(); } } /** * @author truly * @date 2023/3/01 24:24 * @Description: 工厂方法实现 解决简单工厂存在的问题 */ //返回一个共同接口 //可任意定制生成过程--------moveable xxxFactory.create() public class CarFactory { public Moveable createCar(){ retrun new Car(); } } -------------------------------------------------------------------------------------------------------------------------------- //任意定义产品族 //食物 public abstract class Food { abstract void eat(); } //出行 public abstract class Vehicle { abstract void go(); } //---------------------------抽象工厂------------------------------ public abstract class AbstractFactory { //可以生成一系列的产品族 abstract Food createMike(); abstract Vehicle createVehicle(); } public class Car extends Vehicle{ go(){ xxxxxxxxxxxxxx实现 } } //如现代工厂继承该抽象工厂,就生成现代的食物和交通工具 public class modernFactory extends AbstractFactory(){ @Override Food createMike(){ retrun new Bread(); } @Override Vehicle createVehicle(){ retrun new Car() } }
简单工厂方便于产品的扩展,只需要加新产品就可以了,
抽象工厂方便于产品族扩展,但是对产品扩展不方便(产品抽象方法得增加,实现方法也得增加)
更好的解决方案
五、Facade门面者模式
含义:例如你去政府机构办事,需要从A部门后再去B部门,然后再去C部门,D部门,这时候就需要一个门面模式提供一个统一接口,我只要去找门面,他就能帮我去协调各个部门内部关系(相当于代办人)。
-
含义:相当于一个系统内部,有多个部门需要相互协调,如果新增部门,则需要和很多系统打交道,那就可以抽出一个专门部门,所有部门都和该部门打交道。
MQ中间件就是使用的门面-调停者模式
六、Decorator装饰器模式
1 2 3 4 5 6 7 8 9 GameObject | | bullet------------------------GoDecorator | | |-------------------| | | RectDecorator TailDecorator
这样子弹想要加外壳和尾巴就可以将new一个RectDecorator(GameObejct bullet),然后再将处理后的对象放入new的尾巴装饰器中
待更新….
七、责任链模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class FilterChain(){ Filter filters=new ArrayList(); public void add(Filter f){ filters.add(f); } public void dofilter(String str){ for(Filter:f:filters){ f.doFilter(str); } } } //可以进一步优化,在add时可以实现链式编程 public class FilterChain(){ Filter filters=new ArrayList(); public FilterChain add(Filter f){ filters.add(f); retrun this; } public void dofilter(String str){ for(Filter:f:filters){ f.doFilter(str); } } } //继续完善,实现同一个接口,在add时可以再传入一个FilterChain public class FilterChain() implements Filter{ Filter filters=new ArrayList(); public FilterChain add(Filter f){ filters.add(f); retrun this; } public void dofilter(String str){ for(Filter:f:filters){ f.doFilter(str); } } }
1 2 3 4 5 6 7 8 public Bolean dofilter(String str){ for(Filter:f:filters){ if(!f.doFilter(str)){ retrun false; } } retrun true; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class FilterChain(){ Filter filters=new ArrayList(); //加入一个索引,标明当前是哪一个filter int index=0; public void add(Filter f){ filters.add(f); } public boolean dofilter(Request resquest,Response respone,FilterChain chain){ //已经执行完该链条,返回false if(index==filters.size()) retrun false; //拿到当前过滤器 filter=filters.get(index); index++; //调用当前过滤器的dofilter retrun filter.doFilter(resquest,response,chain); } } } class HTMLFilter implements Filter{ public void dofilter(Request resquest,Response respone,FilterChain chain){ //request逻辑处理 //调用链条的dofilter chain.dofilter(request,response,chain); //response的处理-----这样顺序就倒过来了 } }
八、Observe观察者模式
理解:观察者模式通常包含以下三个类…..
事件源:被观察者,发出事件的对象
观察者:等待事件的对象
事件:被发出的对象(Event基类中有个getResource方法,获取事件源)
大多数情况下,我们观察者处理事件时,需要事件源对象,那就可以传入事件对象,使用具体事件实现的getResource方法
九、Composite组合模式 PS:树状结构专用模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 package compositeMode; import java.util.ArrayList; import java.util.List; /** * @author truly * @date 2023/3/5 22:16 * @Description: Composite组合模式demo */ public class CompositeModeDemo { public static void main(String[] args) { BranchNode root = new BranchNode("root"); BranchNode chapter1 = new BranchNode("chapter1"); BranchNode chapter2 = new BranchNode("chapter2"); LeafNode c11 = new LeafNode("c11"); LeafNode c12 = new LeafNode("c12"); BranchNode selection21 = new BranchNode("selection21"); LeafNode c211 = new LeafNode("c211"); LeafNode c212 = new LeafNode("c212"); root.add(chapter1); root.add(chapter2); chapter1.add(c11); chapter1.add(c12); chapter2.add(selection21); selection21.add(c211); selection21.add(c212); tree(root,0); } static void tree(Node n,int depth){ for (int i=0;i<depth;i++) { System.out.print("--"); } n.p(); if (n instanceof BranchNode){ for (Node node :((BranchNode) n).nodes){ tree(node,depth+1); } } } } abstract class Node { abstract public void p(); } class LeafNode extends Node { String content; public LeafNode(String content) { this.content = content; } @Override public void p() { System.out.println(content); } } class BranchNode extends Node { List<Node> nodes = new ArrayList(); String name; public BranchNode(String name) { this.name = name; } @Override public void p() { System.out.println(name); } public void add(Node node) { nodes.add(node); } }
十、Flyweight享元模式 PS:重复利用对象(共享元数据,类似活字印刷)
理解:就如线程池,池化思想,JAVA中的Stirng就是使用享元模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package compositeMode; import java.util.ArrayList; import java.util.List; /** * @author truly * @date 2023/3/5 22:16 * @Description: Flyweight享元模式demo */ public class FlyweightDemo { String s1="abc"; String s2="abc"; //放入常量池,没有则放入,有则直接拿来使用 String s3=new String("abc"); Strinh s4=new String("abc"); s1==s2 //true s1==s3 //false s3.intern() //true intern方法为s3内部指向常量池的应用 }
主要有如下应用
结合Compsite模式,就如ABABABABA就可以由A和B两个元组合而来
十、Proxy代理模式
理解:静态代理:基于接口实现,会产生较多代理类
动态代理:
cglib字节码方式:基于子类实现代理
JDK代理:基于实现同一接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package compositeMode; import java.util.ArrayList; import java.util.List; /** * @author truly * @date 2023/3/5 22:16 * @Description: Flyweight享元模式demo */ public class FlyweightDemo { String s1="abc"; String s2="abc"; //放入常量池,没有则放入,有则直接拿来使用 String s3=new String("abc"); Strinh s4=new String("abc"); s1==s2 //true s1==s3 //false s3.intern() //true intern方法为s3内部指向常量池的应用 }
主要有如下应用
结合Compsite模式,就如ABABABABA就可以由A和B两个元组合而来
十一、原型模式 理解:其实就是通过复制、克隆去创建一个一样的对象
包括深浅复制两种方法:
十二、构建者模式 理解:如果工厂模式是批量生产产品,那构建者就是私人定制化产品。
一般来说,读取配置文件产生对象时,最好选择构建者模式,因为配置文件中的配置信息可有可无。
角色
产品角色:要构建的具体对象
导演角色:导演该产品如何构建,使用builder的。
构建者角色:提供构建表示(属性外露)