23种设计模式

23种设计模式

#本质
面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的理解
#软件设计原则
1.开闭原则:对扩展开放,对修改关闭:接口和抽象类,使用多个实现类
2.里式代换原则:子类可以扩展父类的功能,但是不修改或重写父类方法:传参时父类参数传入子类参数也    是一样的效果。
3.依赖倒置原则:高层模块不应该依赖低层模块:controller--service不要依赖serviceImpl
4.接口隔离原则:接口内方法尽量独立:一个实现类继承多个接口时无须实现冗余方法
5.迪米特法则:降低类之间的耦合,只和自己有关系的类进行交流
6.合成复用原则:尽量使用组合和聚合等关联关系实现,其次才考虑使用继承关系:继承关系为“is-a”(是一个),组合关系为“has-a”(有一个)即作为一个属性放到新类中

类图UML:

#类使用包括:类名、属性和方法 见图一
#1.+ 表示public 2.- 表示private 3. # 表示protected
#属性: 可见性 名称 :类型 [ =缺省值]
#方法: 可见性 名称(参数列表) [:返回值]

#类和类关系
#1.单向关联 图二 2.双向关联 图三 3.自关联 4.聚合关系 图四5.组合关系 图八 6.依赖关系 图七 7.继承关系 图五 8.实现关系 图六

图一: 在这里插入图片描述

图二:在这里插入图片描述

图三:在这里插入图片描述

图四:在这里插入图片描述

图五:在这里插入图片描述

图六:在这里插入图片描述

图七:在这里插入图片描述

图八:在这里插入图片描述

创建者模式

#将对象的创建和使用分离,以此降低系统的耦合度。
#工厂方法模式VS抽象工厂模式VS建造者模式
    工厂方法模式注重整体对象的创建:连接池,参数配置一次后固定,创建连接即可
    抽象工厂模式注重是同一种产品族的构建
    建造者注重部件的构建的过程:每个参数都自己填,然后调用方法,见建造者模式拓展
#例子:抽象工厂是汽车配件生产工厂,建造者是汽车组装工厂

单例模式

//针对于一个类:此类自己创建自己的对象,并确保只有一个对象被创建
//饿汉式:类加载的时候对象被创建
//懒汉式 类加载时不会被创建,首次使用的时候才会被创建
//饿汉式三种:
public class Singleton{//饿汉式1
    private Singleton(){}
    private static Singleton instance  = new Singleton();
    public static Singleton getInstance(){
        return instance;
    } 
}
public class Singleton {//饿汉式2静态代码块
    private Singleton(){}
    private static Singleton instace;
    static {
        instace = new Singleton();
    }
    public static Singleton getInstance(){
        return instace;
    }
}
public enum Singleton {//饿汉式3
    //枚举类型:不会被破坏,因为jvm定义枚举类型不允许被反射,且他没有无参构造
    INSTANCE;
    //其他业务方法...
}
//懒汉式3种:
public class Singleton {//懒汉式1:
    //synchronized加了线程安全,否则线程不安全
    private Singleton() {}
    private static Singleton instace;
    public static synchronized Singleton getInstance() {
        if(instace==null) {
            instace = new Singleton();
        }
        return instace;
    }
}
public class Singleton {//懒汉式2
    //双重检验锁:线程安全;但是多线程可能会出现空指针(JVM进行指令重排序)
    //volatile关键字可以解决指令重排序问题,以及可见性问题
    private Singleton() {}
    private volatile static Singleton instance;
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
public class Singleton {//懒汉模式3
    //线程安全
    //静态内部类:jvm加载类的时候不会加载内部类,只有内部类使用时才会被加载
    //static修饰保证对象只会被实例化一次,且保证顺序
    private Singleton() {}
    private static class SingletonHolder{
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}
//ps :静态内部类可以改成内部枚举类饿汉/懒汉式;

/**
破坏单例模式:枚举类型不会被破坏
*/
//单例类实现Serializable,进行序列号,反序列化操作后,就会得到不同对象,表明已破坏
//通过反射获取对象
/**
解决方式(静态内部类方式演示):
    单例模式类中增加下面的方法,在序列号和反射时会自动调用;源码中有判断
*/
public Object readResolve(){
    return SingletonHolder.INSTANCE;
}
//也可以自己实现:
 //添加静态变量(红绿灯),此时也有可能被破坏,可以反射获取flag的值并修改
    private static boolean flag = false;
    private Singleton() {
        //在私有构造方法中添加:
        synchronized (Singleton.class){
            if(flag){
                throw new RuntimeException(("单例类不可创建两次");
            }else {
                flag = true;
            }
        }
    }
单例应用
//java 类中的使用例子: Spring中加载Bean
    //Runtime 标准的饿汉式
    Runtime runtime = Runtime.getRuntime();
    Process exec = runtime.exec("ipconfig");//获取系统的ip相关,相当于cmd执行命令
    byte[] arr = new byte[1024*1024*100];
    int read = exec.getInputStream().read(arr);
    System.out.println(new String(arr,0,read,"GBK"));

工厂模式

#简单工厂模式(不属于23种涉及模式之一)更像是一种编码习惯,使用new创建对象
    #角色:1.抽象产品 2.具体产品 3.具体工厂
    #问题:违反开闭原则 简单工厂和具体产品还是耦合,加产品势必改工厂;但是调用工厂的客户端可能很多,这时只需要修改一个地方即可。
#静态工厂模式:简单工厂的方法设置为静态方法,优缺点一样
#工厂方法模式(23之一)
    #角色:1.具体工厂 2.抽象工厂 3.具体产品 4.抽象产品
    #例子:抽象工厂中有生产电脑的方法,各个具体工厂是各个品牌的生产电脑的方法,新增品牌时直接       创建新的具体工厂类,符合开闭原则
    #缺点:每增加一个产品就需要增加一个新的具体工厂类,增加复杂度

抽象工厂模式

#和工厂方法模式角色相同
#不同点:抽象工厂模式可以创建多种工厂:抽象工厂里面不仅可以生产电脑;还可以生产电源,内存等,这些东西对应其具体工厂(联想一个工厂,华硕一个工厂类),所以增加产品,不需要新增工厂类。
#缺点:新增具体产品,需要修改所有的具体工厂类和抽象工厂类
#使用场景:输入法换皮肤,会把所有的图标什么的一起更换,他们属于一个工厂

工厂模式拓展

#jdk源码使用:1.Collection.iterator方法用了工厂方法模式
#Collection接口时抽象工厂,ArrayList是具体工厂 Iterator接口时抽象产品类,ArrayList中的成员内部类是具体的产品类(new 了对象)
#2.DateFormat和Calendar中getInstance()也是工厂模式

#简单工厂+配置文件解耦  #Spring IOC容器的原理
    #创建bean类放到配置文件中全类名,通过反射加载
    #例:配置文件:
    aaa: com.lmy.test.Person
    bbb: com.lmy.test.ITPerson
public class lmyFactory {
    //定义一个容器
    private static Map<String, Object> hashMap = new HashMap<>();

    //静态代码块加载配置文件
    static {
        Properties properties = new Properties();

        try (InputStream ras = lmyFactory.class.getResourceAsStream("bean.yml")) {
            properties.load(ras);
            Set<Object> objects = properties.keySet();
            for (Object obj : objects) {
                String className = properties.getProperty((String) obj);
                Class<?> aClass = Class.forName(className);
                Object o = aClass.newInstance();
                hashMap.put((String) obj, o);
            }
        } catch (IOException e) {
            throw new RuntimeException("加载失败");
        } catch (IllegalAccessException|InstantiationException|ClassNotFoundException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public static Object getPersonFactory(String s) {
        return hashMap.get(s);
    }
}

原型模式

#通过已经创建的实例作为原型,复制该实例来创建一个相同的对象
#角色:1. 抽象原型类:必须实现clone方法 2.具体原型类:实现clone 3. 使用类:使用clone方法
#Java中Cloneable接口就是抽象原型类

#浅拷贝:创建一个新对象,新对象的属性与原来对象完全相同,基本类型和String是新的,引用类型指向		原地址
#深拷贝:创建新对象,不再指向原对象地址(如序列化可以深克隆,效率低)
#默认方式实现clone方法:是一种浅拷贝;
#深克隆:实现每一个类的引用类型的属性的clone方法:在clone方法中加 引用类型属性.clone()
#应用场景:1.一般用于不可变对象的创建 2.工厂模式+原型模式一起使用

建造者模式

#将构建与装配解耦。同种装配方式可以创建不同的构建结果:用于复杂对象的创建
#角色:1. 抽象建造者类:抽象创建方法
	#2.具体建造者类 :实现创建方法(新的产品可以创建新的具体建造者,不用动其他的)
	#3.产品类:要创建的对象 
	#4.指挥者类:调用具体建造者进行某种顺序的创建
	#ps:具体建造者类和指挥者类可以写成一个类,简化系统结构;即把建造方法写在抽象建造者中,但			是这种方式加重了抽象建造者的职责,不太符合单一职责原则
#适用:构建的产品一般具有相似的特点;存在较大差异不适合适用该模式

#模式拓展:可读性方式:
	#原来方式:Phone phone = new Phone("内存","CPU","...");
	#使用建造者模式之后:Builder为静态内部类
	#Phone phone = new Phone().Builder().build()
    								#.cpu("CPU")
    								#.nc("内存")...						

结构型模式

//描述的是对象与对象之间的关系,或者组成一个更复杂对象结构的模式


//静态代理VS装饰者区别
//相同点:1.都要实现和目标类相同的业务接口 2.都要声明目标对象 3.都可以不修改目标类增强其方法
//不同点:1.目的:装饰者为了增强目标对象;静态代理为了保护隐藏目标对象 2.装饰者获取目标对象从外界传递,可以通过构造方法传递;静态代理在代理类中创建

代理模式

//优缺点:可以保护目标对象,可以拓展目标对象功能,降低系统耦合度;但是增加系统复杂度
//使用场景:远程代理:RPC框架的思想;防火墙代理:vpn;保护代理:设置访问权限级别

//静态代理:编译期直接生成
//角色:1.真实对象类 2.代理对象类:可以拓展真实对象的功能 3.抽象主题类
	//客户端使用代理对象类;代理对象类和真实对象类都需要实现抽象主题类

//ps:获取动态代理的全类名,然后使用阿里巴巴开源的jar包诊断工具**arthas**,执行java -jar 工具包,然后选择2,然后执行jad 全类名,就会生成该类的class反编译的java文件。

//动态代理:动态生成,有JDK代理和CGLIB代理
	//JDK:jdk代理的目标对象必须有接口;提供一个代理类工厂Proxy,该类提供一个创建代理对象的		静态方法(newProxyInstance)获取代理类对象(对应2);
	//工厂类代码:
public class JDKProxy{
	 //声明一个真实对象类 
    private TestC test = new TestC();
    //生成代理对象的方法 InterA是抽象主题类
    public InterA getProxy() {//getProxy(Class target)
        //实际使用中会把真实对象类的类对象作为参数,然后结合其他的涉及模式使用
        return (InterA) Proxy.newProxyInstance(test.getClass().getClassLoader(),
                test.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] 						args) throws Throwable {
                        //增强逻辑,前置增强演示,还可以后置环绕等;
                        System.out.println("代理对象进行了代理");
                        return method.invoke(test, args);
                    }
                });
    }
}
	//CGLIB代理:无需定义接口,引入cglib jar包即可使用,使用asm字节码生成框架,比jdk1.6之		前速度较快,但是1.8之后jdk优化,jdk较快;
	//注意:CGLIB是动态生成目标对象类的子类的代理对象,所以不能代理final声明的类或方法!!!
	//需要实现MethodIntercepterl接口
public class CGLIBFactory implements MethodInterceptor{
    //声明一个真实对象类,
    private TestC test = new TestC();
    //生成代理对象的方法
    public TestC getProxy() {//getProxy(Class target)
        //实际使用中会把真实对象类的类对象作为参数,然后结合其他的涉及模式使用
        Enhancer enhancer = new Enhancer();
        //设置父类的字节码对象
        enhancer.setSuperclass(test.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //创建代理对象
        return (TestC)enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //增强逻辑,前置增强演示,还可以后置环绕等;
        System.out.println("CGLIB代理对象");
        return method.invoke(test, objects);
    }
}
//三种代理对比:原理不同,具体看上面;有接口时一般使用jdk,无接口对象使用CGLIB
//动态代理比静态代理好处就是,接口中声明的方法被集中处理,增加方法直接修改真实对象类即可

适配器模式

//分为类适配器模式和对象适配器模式(后者耦合性较低,使用范围广)
//作用:讲一个接口转换为另一个客户希望的接口(目标接口)
//角色: 1.目标接口:抽象类或接口(USB) 2.适配者类:需要适配的类(网线) 3.适配器类(转换器)
//适配器和适配者都会实现目标接口

//类适配器模式:适配器类需要实现目标接口,继承适配者类,耦合性强。违背合成复用原则
//对象适配器模式:只实现目标接口!把适配者类作为类属性并使用有参构造赋值。
//接口适配器模式:使用抽象Adapter类实现目标接口所有方法,适配器继承抽象类实现需要的方法

//应用场景: 1.使用第三方组件,但是组件的接口定义与自己的要求不同时
		//2.以前开发的系统无法满足新系统功能的需求

//jdk源码使用:InputStream(字节流,客户需要类)转Reader(字符流,目标接口)的适配器是InputStreamReader(将字节输入流转换为能读取字符的字符输入流).
//InputStreamReader继承于java.io中的Reader,对其抽象未实现方法进行实现
//InputStreamReader类中属性适配者类(StreamDecoder)继承了Reader。

装饰者模式

//不改变原有对象结构情况下,动态给对象增加额外功能
//角色: 1.抽象构件角色(快餐) 2.具体构件:缺少功能的类(炒面、炒饭) 3.抽象装饰:继承或实现抽象构件角色 4.具体装饰(鸡蛋、培根等)
//好处:是继承的一个替代模式,可以多台扩展一个实现类的功能
//使用场景:1.类不易使用继承的情况:1).大量继承子类过多 2).final修饰的不能继承的类
		//2.不影响其他类,单独给某个类添加职责
//JDK源码应用: IO流的包装类 BufferedInputStream,BufferedOutputStream,BufferedReader,BuffereWriter等
//Writer:抽象构件 ,InputStreamWriter:具体构件  BufferedWriter:继承聚合了Writer,装饰者类:增强了Writer功能,增加了缓存区,提高了数据读取效率

桥接模式

//将抽象和实现分离,使他们可以独立变化。组合关系替换继承关系
//角色:1.抽象化角色(包含实例化对象的引用) 2.扩展抽象化角色(实现抽象化角色,并使用引用调用实现化角色的方法)3.实现化角色 4.具体实现化角色
//好处:提高扩展性,实现细节对客户透明
//使用场景:1.当一个类存在两个独立变化的维度,且这两个维度都需要拓展

外观模式 || 门面模式

//迪米特法则的典型应用,为多个复杂子系统提供一个统一的接口,使这些子系统更容易被访问
//角色: 1.外观角色(类中聚合子系统角色实例,如智能音箱) 2.子系统角色(灯、冰箱、TV、空调等)
//好处:降低子系统和客户端的耦合度,减少客户端处理逻辑
//缺点:不符合开闭原则,修改麻烦
//使用场景:统一的接口供外界访问
//JDK源码: tomcat作为web容器时,接收浏览器请求,封装成ServletRequest对象(ServletRequest是一个接口,HttpServletRequest是其子接口,RequestFacade实现了子接口,典型的外观角色)
//spring JDBC 中的外观模式
//Mybatis中的外观模式
//SLF4J 中的外观模式

组合模式

//部分整体模式:把一组相似的对象当成一个单一的对象(文件夹下面有文件和文件夹,把文件当成一类,文件夹一类)
//角色:1.抽象根节点(定义树枝和叶子共有的功能) 2.树枝节点(继承根节点,如文件夹) 3.叶子结点(继承根节点,如文件)
//优点:分层次区分复杂对象,减少客户端复杂性
//使用场景: 为树形结构而生

享元模式

//通过共享技术提供对象的复用,减少创建对象,减少系统开销,提高利用率
//状态:内部状态:不会随环境改变而改变的可共享部分;外部状态:随着环境改变而改变的不可共享部分。享元模式就是区分这两种状态,并将外部状态外部化
//角色:1.抽象享元角色 2.具体享元角色(通常结合单例模式) 3.非享元角色 4.享元工厂角色(单例的,检查系统是否存在具体享元对象,没有新建)
//实例:俄罗斯方块:方块共享;方块颜色不共享,外部化
//优点:减少对象的创建,节省内存;外部状态相对独立,且不影响内部状态
//使用场景:对象的大部分状态可以外部化并赋值到对象中;需要维护一个享元池,多次使用享元对象时使用该模式
//JDK源码:Integer类:维护了一个[-128,127]的享元池

行为型模式

//描述程序在运行时复杂的流程控制;分为 类行为模式和对象行为模式
//前者采用继承机制
//后者采用组合或聚合方式,比前者更灵活,符合合成复用原则
//模板方法模式和解释器模式是类行为模式,其他的均为对象行为模式

模板方法模式

//角色: 1.抽象类:
		//1)模板方法:定义某种顺序调用的方法(一般final修饰,不可修改) 2)基本方法:实现顺序中各步骤的方法分为抽象方法,由子类实现;具体方法,直接实现且子类可以重写;钩子方法,直接实现一般用于判断,方法名一般为isXxx并返回boolean类型,可以重写
	//2.具体子类:实现抽象方法和钩子方法
//优点:提高代码复用性,实现了控制反转
//缺点:方法由子类实现,提高了代码阅读难度
//适用场景:算法整体步骤很固定时使用
//JDK源码:InputStream类,定义了多个read()方法,无参read()被其子类重写

策略模式

//定义:定义一系列算法并将他们封装起来,使他们相互可以替换,不影响使用方
//角色:1.抽象策略类 2.具体策略类 3.环境类:持有策略类引用参数构造方法给客户端调用
//JDK源码: Comparator类:在Arrays类(环境类)中有一个sort方法,传入的就是Comparator抽象策略类

命令模式

//定义:将一个请求封装成一个对象,将发出请求的责任和执行请求的责任分开,两者通过命令对象进行沟通,管理
//角色:1.抽象命令类 2.具体命令类(持有接收者,调用其方法执行) 3.实现者/接收者角色(真正执行命令的对象) 4.调用者/请求者角色:通常持有多个命令对象,供客户端调用
//案例:服务员属于4;厨师属于3;命令类中包含下订单等命令
//优缺点:降低系统耦合度,但是可能有过多的具体命令类
//结合组合模式使用,将多个命令组合成一个命令;结合备忘录模式,实现命令的撤销和恢复
//使用场景:请求排队
//jdk源码:Runable接口:抽象命令角色;Thread:调用者类;程序员自定义具体命令者角色实现Runable,类中含有接收者类

职责链模式

//定义:为了避免请求者与多个处理者耦合,将所有请求处理者通过前一对象记住下一个对象的引用形成一条链,请求到来时,一直到可以处理它的对象为止
//角色:1.抽象处理者角色:包含抽象处理方法和后继对象引用及调用后继对象方法调用(final修饰,作用:如果可以处理则处理,不可处理转发给后继者) 2.具体处理类角色:实现抽象处理方法 3.请求角色:创建处理链,提交请求
//优缺点:简化了对象之间的联系;每个类只需要处理应该处理的工作,不需要其他所有处理者的引用;但是不能保证所有请求一定被处理,主要靠客户端保证,增加了客户端的复杂性
//JDK源码:Filter(过滤器)是典型应用:自定义的Filter是具体处理类角色,FilterChain是责任链对象(后继对象)

状态模式

//针对于有状态的对象:不同状态执行不同的方法的类。final int OPEN_STATUS = 1;
//角色:1.环境角色:定义一个客户需要的接口,维护一个状态,把不同状态交给具体状态对象处理final int OPEN_STATUS = new OpenStatus();   2.抽象状态角色(声明环境角色) 3.具体状态角色:实现状态的行为
//优缺点:将某个状态放到一个类中处理,方便增加新的状态;但增加了很多类
//使用场景:一个对象的行为取决于它的状态,并且每个状态都有庞大的分支

观察者模式

//定义:发布-订阅模式,定义了一种一对多的关系,让多个观察者监听同一个对象,对象状态变化时,进行更新操作
//角色:1.抽象主题(被观察者):引用观察者对象及相关方法 2.具体主题对象:将状态存入具体观察者对象,发生变化时给观察者发送通知 3.抽象观察者 4.具体观察者 
//主题角色持有多个观察者对象引用(通知观察者即调用其方法)
//使用场景:对象间存在一对多,且一个对象改变会影响其他对象
//jdk源码:java.util.Observable类和java.util.Observer接口定义了观察者模式,实现他们的子类即可实现观察者模式
//Observable:抽象主题类,有一个Vector集合成员变量和三个方法
//Observer:抽象观察者 重写update方法即可

中介者模式

//定义:多个类之间关系复杂,相互关联时呈现复杂的网状结构,中介者模式就是把这种结构改成星型结构
//角色:1.抽象中介者角色:提供同事对象注册与转发同事对象的抽象方法
	//2.具体中介者:实现接口,定义list管理同事对象及其关系  如房屋中介
	//3.抽象同事类:保存中介者对象,提供本身行为抽象方法,实现所有影响其他同事类的公共方法 如都是人
	//4.具体同事类:实现抽象方法   如房主与租房者

迭代器模式

//定义:提供一个对象来顺序访问聚合对象的数据,而不暴露聚合对象的内部表示
//角色: 1.抽象聚合角色:定义存储、添加、删除及创建迭代器对象的接口
	//2.具体聚合角色:实现类,返回具体迭代器对象
	//3.抽象迭代器角色:定义访问和遍历聚合元素的接口 4.具体迭代器角色
//JDK源码:Iterator:抽象迭代器 Itr(ArrayList的私有静态内部类):具体迭代器类 List:抽象聚合类 ArrayList:具体聚合类;使用迭代器模式时,只需要我们自定义的容器类实现Iterator接口并返回其实现类对象即可

访问者模式

//定义:封装一些作用于某种数据结构的各元素的操作,它可以不改变原数据结构
//角色:1.抽象访问者角色:定义了对每一个元素访问的行为		--给宠物喂食的人
	//2.具体访问者角色:实现访问的具体行为				 --主人、其他人
	//3.抽象元素角色:定义接受访问者的方法,每个元素都可以被访问	-- 动物抽象类
	//4.具体元素角色:实现方法,通常实现情况是使用访问者提供的去访问元素类的方法 -- 宠物狗、猫
	//5.对象结构角色:一般含有一组元素并提供访问者访问方法		-- 主人家
//拓展: 1.分派:根据对象的类型进行方法的选择--分为静态分派和动态分派
//Map map = new HashMap(); map变量的静态类型是Map,实际类型是HashMap; jvm编译时期仅知道对象的静态类型,而方法执行时则是根据对象的实际类型。
//1.1 静态分派是指发生在编译时期,分派根据静态类型信息发生(方法重载支持静态分派,重载时会执行Map中方法(举例))
public class Execute{
    public void execute(Animal a){
        sout("animal")
    }
     public void execute(Dog d){
        sout("Dog")
    }
    public static void main(String[] args){
        Animal a = new Animal();
        Animal d = new Dog();
        Execute exe = new Execute();
        exe.execute(a);
        exe.execute(d);
        //输出 animal animal
    }
}
//1.2 动态分派是指发生在运行时期,动态分派置换某个方法(方法重写支持动态分派)//重写时输出animal Dog
//2.双分派:在重载方法委派的前面加上继承体系中的方法重写的环节,就会使重载是动态的
public class Animal{
    public void accept (Execute exe){
        exe.execute(this);
    }
}
public class Dog extends Animal{
    /*可不写
    public void accept (Execute exe){
        exe.execute(this);
    }*/
}
public class Execute{
    public void execute(Animal a){
        sout("animal")
    }
     public void execute(Dog d){
        sout("Dog")
    }
    public static void main(String[] args){
        Animal a = new Animal();
        Animal d = new Dog();
        Execute exe = new Execute();
        a.accept(exe);
        a.accept(exe);
        //输出 animal Dog
    }
}
//访问者模式用的就是双分派,实现动态绑定的效果

备忘录模式/快照模式

//定义:提供了一种状态恢复的实现机制,使用户可以方便回到某个特定的步骤;在不破坏封装性的前提下,铺货一个对象的内部状态,并保存以便恢复
//角色:1.发起人角色:记录当前时刻的内部状态,提供创建和恢复备忘录的功能,可以访问备忘录中信息
	//2.备忘录角色:负责存储发起人的内部状态(与发起人角色属性相同),需要时提供给发起人
	//3.管理者角色:对备忘录进行管理,提供保存获取功能,但是不能访问与修改

	//窄接口:管理者对象或其他非发起人对象看到的是备忘录的窄接口,不具备访问与修改功能
	//宽接口:与窄接口相反,供发起人角色使用


//白箱 备忘录模式:备忘录角色对任何对象都提供一个宽接口,内部状态对所有对象公开
	//需要程序员自律维护类的封装性

//*************************//
//黑箱 备忘录模式:备忘录角色对发起人角色提供宽接口,为其他对象提供窄接口:将备忘录类设计成发起人类的内部成员类即可实现双重接口。
	//结构:1.备忘录接口(窄接口),2.发起人角色类--3.内部类备忘录角色实现备忘录接口

//使用场景:1.需要保存与恢复数据的场景,如游戏的存档、word/记事本等需要保存回滚的情况

解释器模式

//给定一个语言,定义它的文法,并定义一个解释器,解释器使用该标识解释语言中的句子含义
//解释器包含:文法/语法规则(例加减法)和抽象语法树(简称语法树例a+b-c*d)
//角色:1.抽象表达式角色:定义解释器接口,约定解释操作 interpret(Context context)抽象方法
	//2.终结符表达式角色:抽象表达式子类,实现文法中与终结符相关的操作 -加减操作
	//3.非终结符表达式角色:抽象表达式子类,实现文法中与非终结符相关的操作 -变量表达式类
	//4.环境角色:通常包含各个解释器需要的数据或公共功能 -计算出客户端表达式结果
	//5.客户端角色:将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树 -定义a+b-c等语法树

Spring中应用

#IOC容器: 
#工厂模式
#单例模式:IOC的单例不是通过构造器创建的对象,而是spring框架对每一个bean只创建了一个对象
#模板方法模式 AbstractApplicationContext类中的 finishBeanInitialization()调用了子类的getBean()方法,因为getBean()的实现与环境息息相关
#迭代器模式:对于MutablePropertyValues类定义使用了迭代器模式,因为此类存储并管理PropertyValue对象,也属于一个容器
#另外spring的aop用到了代理模式;选择JDK代理和CGLIB代理使用的是策略模式,还有适配器模式、装饰者模式、观察者模式等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

没有什么是应该

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值