设计模式
设计模式类型
设计模式分为三种类型:
创建型模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。
结构性模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
行为型模式:模板方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)
设计模式的目的
代码重用性;
可读性;
可扩展性;
可靠性;
促使高内聚,低耦合,提高软件的可维护性,通用性和扩展性,并降低软件的复杂度;
设计模式的原则
单一职责
接口隔离
依赖倒转:面向接口编程
里氏替换:子类中尽量不要重写父类的方法,因为继承会让两个类耦合性增强了。在合适的时候,可以通过聚合、组合、依赖来解决问题
开闭原则:对扩展开放,对修该关闭。用抽象构建框架,用实现扩展细节。
迪米特法则:一个类对自己依赖的类知道的越少越好,从而减少耦合性。
合成复用:尽量使用合成/聚合的方式,而不是使用继承。
面向对象->功能模块【设计模式+算法【数据结构】】->框架【使用到多种设计模式】->架构【服务器集群】
使用过什么设计模式,怎用使用的,解决了什么问题
创建型模式
单例设计模式
采取一定的方法保证在整个的软件系统中,对,某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。例如Hibernate 的SessionFactory
单例的八种方式
饿汉式(静态常量)
构造器私有化
类的内部创建对象
向外暴露一个静态的公共方法
饿汉式(静态代码块)
懒汉式(线程不安全)
懒汉式(线程安全,同步方法)
懒汉式(线程安全,同步代码块)
双重检查(推荐)
静态内部类(推荐)
枚举(推荐)
源码中
JDK中java,lang.Runtime
使用场景
频繁的进行创建和销毁的对象、创建对象耗时过多或耗费资源过多但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(如数据源、session工厂)
抽象工厂模式
工厂模式
简单工厂模式
源码中
JDK中的Calendar类中使用了简单工厂模式
工厂方法模式
定义了一个创建对象的抽象方法,由子类决定要实例化的类,工厂方法模式将对象的实例化推迟到子类
抽象工厂模式
定义了一个interface用于创建相关或有依赖关系的对象簇。
将实例化的代码提取出来,放到一个类中同一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护
创建对象实例时,不要直接new类,而是把这个new类的动作放在一个工厂的方法中,并返回。
不要让类继承具体类,二十继承抽象类或者时实现interface接口
不要覆盖记录中已经实现的方法
原型模式
原型实例知道创建对象的种类,并且通过拷贝这些原型,创建新的对象
深拷贝与浅拷贝
浅拷贝使用默认的clone()方法实现
深拷贝通过重写clone方法来实现以及通过对象序列化实现
源码中
Spring 中原型bean的创建
建造者模式
可以将复杂对象的建造过程抽象出来,使这个抽象过程的不同实现方法可以构造出不同表现的对象
源码中
java.lang.StringBuilder
结构型模式
装饰者设计模式
动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更具有弹性,装饰着模式也体现了开闭原则。
源码中
Java的IO结构,FileInputStream使用到了装饰者模式
应用场景
适配器设计模式
将口哦个类的接口转换成客户期望的另一个接口表示,主要目的时兼容性。
分为三类:类适配器模式、对象适配器模式、接口适配器模式
类适配器
对象适配器
根据合成复用原则,使用组合替代继承,所以它解决了类适配器必须继承的局限性
接口适配器
缺省适配器模式,适用于一个接口不想使用其所有方法的情况。
源码中
SpringMvc中的HandlerAdapter
桥接模式
将实现与抽象放在两个不同的类层次中,使两个层次可以独立改变
源码中
JDBC中的Driver接口
应用场景
JDBC驱动
银行转账系统
转账分类:网上转账,柜台转账,ATM转账
转账用户类型:普通用户,银卡用户,金卡用户
消息管理
消息类型:及时消息、延时消息
消息分类:手机短信,邮件消息,QQ消息
组合模式
部分整体模式,创建了对象组的树形结构,将对象组合成树状结构以表示“整体-部分”的层次关系。
源码中
Java的HashMap使用了组合模式
应用场景
需要遍历组织机构,或者处理的对象据哟树形i二狗时,非常适合使用组合模式。
外观模式
源码中
MyBatis中的Configuration,创建MetaObject
应用场景
享元模式
运用共享技术支持大量细粒度的对象
内部状态和外部状态
将对象的的信息分为两个部分,内部状态和外部状态。内部状态指对象共享出来的信息,存储在享元对象内部且不会随环境的改变而改变,外部状态指对象得依赖的一个标记,是随环境改变而改变的、不可共享的状态。
源码中
JDK中的Interger
应用场景
数据库连接池、String常量池、缓冲池等池技术
代理模式
为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
代理模式分类:静态代理、动态代理(JDK代理、接口代理)和Cglib代理(可以在内存动态的创建对象,而不需要实现接口,他是属于动态代理的范畴)
静态代理
静态代理需要定义接口或者父类,被代理对象(目标对象)与代理对象一起实现相同的接口或者是继承相同父类。
动态代理
代理对象,不需要实现接口,但是目标对象要实现接口,否则不能用动态代理
Cglib代理模式
静态代理和JDK代理模式都需要目标丢向实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理。
在内存中构建一个子类对象从而实现对目标对象功能扩展。它是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口,它广泛的被许多AOP的框架使用,例如Spring AOP,实现方法拦截。
AOP编程中选择代理模式:
目标对象需要实现接口,用JDK代理
目标对象不需要实现接口,用Cglib代理。
Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类。
代理的类不能final,否则报错java.lang.IllegaArgumentException。
防火墙代理
内网通过代理穿透防火墙,实现对公网的访问
缓存代理
当请求图片文件等资源时,先到缓存代理取,如果取到资源则OK,如果取不到资源,再到公网或者数据库取,然后缓存。
远程代理
远程对象的本地代表,通过它可以把远程对象当本地对象来调用。远程代理通过网络和真正的远程对象沟通信息。
同步代理:主要使用在多线程编程中,完成多线程间同步工作。
源码中
应用场景
行为型模式
模板方法
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤。
模板方法模式的钩子方法
源码中
Spring IOC 容器初始化时运用到模板方法模式
应用场景
命令模式
使得请求发送者
源码中
Spring 框架的JdbcTemplate使用了命令模式
应用场景
界面的一个按钮都市一条命令、模拟CMD(DOS命令)订单的撤销/恢复、触发反馈机制。
访问者模式
封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
将数据结构和操作分离,解决数据结构和操作耦合的问题。
源码中
应用场景
需要对一个对象结构中的对象进行很多不同的操作(操作之间彼此没有关联),同时,需要避免让这些操作“污染”这些对象的类。
适合做报表、UI、拦截器于过滤器,这种数据结构相对稳定的系统
迭代器模式
提供一种遍历集合元素的同一的接口,使用一致方法遍历集合元素,不需要知道集合对象的底层表示,不会暴露内部的结构。
源码中
JDK的ArrayList集合中就使用了迭代器模式。
应用场景
观察者模式
对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer变化。
源码中
JDK的Observable类使用了观察者模式
应用场景
中介模式
源码中
应用场景
MVC架构模式,C(Controller 控制器)为中介中
备忘录模式
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样之后就可以将该对象回复大原先保存的状态。
源码中
应用场景
后悔药;打游戏时的存档;Windows里的ctrl+z;IE中的后退;数据库的事务管理;
为了节约内存,备忘录模式可以和原型模式配合使用
解释器模式
是指给定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式)
源码中
Spring 框架中SpelExpressionParser
应用场景
可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
编译器;运算表达式;正则表达式;机器人;
状态模式
主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题,状态和行为时一一对应的,状态之间可以相互转换。
当一个对象的内在状态改变时,允许改变其行为,
源码中
借贷平台,订单的不同状态
应用场景
当一个事件或对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时候,可以考虑使用状态模式。
策略模式
定义算法族(策略组),分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户
把变化的代码从不变的代码种分离出来;
针对接口编程而不是具体类;
多用组合/聚合,少继承(客户通过组合方式使用策略)
避免了使用多重转移语句(if..else if.. else)
源码中
JDK的Arrays的Comparator就使用了策略模式
应用场景
责任链模式
为请求创建了一个接受者对象的链。着中国模式对请求的放者和接收者进行解耦
源码中
SpringMVC-HandlerExecutionChain类就使用到职责责任链模式
应用场景
有多个对象可以处理同一个请求时,如,多级请求、请假/加薪等审批流程、Java Web中Tomcat对Encoding的处理、拦截器
设计模式,在应对变化的需求时,总结了许多模式,提升了系统的可维护性、可扩展性。