设计模式(https://www.w3cschool.cn/shejimoshi/factory-pattern.html)
(经典)对接口编程而不是对实现编程(用Animal a = new Cow(),不用Cow c = new Cow())-https://www.cnblogs.com/gavinzhang/p/6051821.html
(经典)优先使用对象组合而不是继承-看https://baijiahao.baidu.com/s?id=1618211082994155867&wfr=spider&for=pc
设计模式的六大原则
1)开闭原则(对扩展开放,对修改关闭)
2)里氏代换原则(任何基类可以出现的地方,子类一定可以出现,看https://blog.csdn.net/Mr_L_h/article/details/82937706)
3)依赖倒转原则(针对接口编程,不要对实现编程)
4)接口隔离原则(使用多个隔离的接口,比使用单个接口要好)
5)迪米特法则,又称最少知道原则(一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立)
6)合成复用原则(尽量使用合成/聚合的方式,而不是使用继承)
1、工厂模式(关键代码:创建过程在其子类执行)
2、抽象工厂模式(关键代码:在一个工厂里聚合多个同类产品)
3、单例模式(关键代码:构造函数是私有的)
看https://blog.csdn.net/mnb65482/article/details/80458571
类锁、对象锁、方法锁区别https://blog.csdn.net/pengweid/article/details/85711970
懒汉式:线程不安全 线程安全
饿汉式:线程安全(没有达到 lazy loading 的效果)
双检锁/双重校验锁:volatile关键字的体会(volatile具有原子性,,假设两个线程,线程A正在执行instance = new Instance()的操作,而线程B开始执行if(instance==null)的判断,当不存在volatile的时候,因为 new Instance()是一个非原子操作,可能发生无序写入,构造函数可能在整个对象构造完成前执行完毕,线程B可能会看到一个不完整的instance对象,因为java的某些实现会在内存中开辟一片存储对象的区域后直接返回内存的引用,所以线程B判断不为null,而这时候实际上,instance的构造函数还没有执行,从而线程b得到不完整的对象。在 Instance 的构造函数执行之前,会在内存中开辟一片存储对象的区域后直接返回内存的引用,赋值给变量 instance,instance也就可能成为非 null 的,即赋值语句在对象实例化之前调用,此时别的线程得到的是一个还会初始化的对象,这样会导致系统崩溃线程B可能会看到一个不完整的instance对象,因为java的某些实现,所以线程B判断不为null。从而得到不完整的对象。)
登记式/静态内部类:线程安全(达到 lazy loading 的效果)
枚举:这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化,确保反序列换时不会重新构建对象
4、建造者模式(关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系)
Java代码例子好,url例子不好
建顺复sb(建造者模式-构建复杂对象-StringBuilder,工厂模式的区别是:建造者模式更加关注与零件装配的顺序)
5、原型模式(关键代码: 实现克隆操作,在 JAVA 继承 Cloneable,重写 clone()方法)
原重(原型模式-创建重复的对象)
6、适配器模式(关键代码:适配器(adapter)继承或依赖已有的对象,实现想要的目标接口,例如读卡器就是内存卡和笔记本之间的适配器)
7、桥接模式(关键代码:抽象类依赖实现类,抽象化、实现化、桥接)
桥接接口规定的是实现化这一方的实现规则,抽象方会拥有这个桥接接口,调用桥接接口的方法,而真正执行方法的是实现方
java数据库连接JDBC,调用者相当于是抽象方,JDBC相当于桥接接口,执行方就是各个数据库厂商根据JDBC的接口规则进行的功能实现
适配器模式与桥接模式区别:
如果你拿到两个已有模块,想让他们协同工作,那么你使用的适配器。如果你还什么都没有,但是想分开实现,那么桥接是一个选择。
桥接是先有桥,才有两端的东西;适配是先有两边的东西,才有适配器
8、过滤器模式(制定不同的规则来对一组对象进行过滤,然后对过滤结果进行分组,例如对同样一批人进行不同的分组(MALE、FEMALE、SINGLE等))
9、组合模式(又叫部分整体模式,关键代码:树枝内部组合该接口,并且含有内部属性 List,里面放 Component)
组树(树枝和树叶)
Java代码例子好,url例子不好
10、装饰器模式(关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法)
装饰器模式即加额外的功能
例子见https://www.cnblogs.com/jzb-blog/p/6717349.html
装饰器的价值在于装饰,他并不影响被装饰类本身的核心功能。在一个继承的体系中,子类通常是互斥的。比如一辆车,品牌只能要么是奥迪、要么是宝马,不可能同时属于奥迪和宝马,而品牌也是一辆车本身的重要属性特征。但当你想要给汽车喷漆,换坐垫,或者更换音响时,这些功能是互相可能兼容的,并且他们的存在不会影响车的核心属性:那就是他是一辆什么车。这时你就可以定义一个装饰器:喷了漆的车。不管他装饰的车是宝马还是奥迪,他的喷漆效果都可以实现。
在复杂的大型项目中,同一级下的兄弟类通常有很多。当你有五个甚至十个ConcreteComponent时,再想要为每个类都加上“ready?go!”的效果,就要写出五个子类了。毫无疑问这是不合理的。装饰器模式在不影响各个ConcreteComponent核心价值的同时,添加了他特有的装饰效果,具备非常好的通用性,这也是他存在的最大价值。
11、外观模式(也叫门面模式,在客户端和复杂系统之间再加一层,这一次将调用顺序、依赖关系等处理好)
这种模式需增加一个单一的类,该类把接口与实现都提供出来,简化调用者调用。
12、享元模式(用于减少创建对象的数量,关键代码:用 HashMap 存储这些对象)
应用实例: 1、JAVA 中的 String,如果有则返回,如果没有则创建一个字符串保存在字符串缓存池里面。 2、数据库的数据池。
13、代理模式(一个类代表另一个类的功能,键代码:实现与被代理类组合)
代理模式和适配器模式应该说很相像,但是他们的区别也很明显,代理模式和被代理者的接口是同一个,只是使用中客户访问不到被代理者,所以利用代理间接的访问,而适配器模式,是因为接口不同,为了让用户使用到统一的接口,把原先的对象通过适配器让用户统一的使用,大多数运用在代码维护的后期,或者借用第三方库的情况下 ,
而外观模式,是大家经常无意中使用的,就是把错综复杂的子系统关系封装起来,然后提供一个简单的接口给客户使用,就类似于一个转接口,可以想象成一个漏斗,中间细的那一段,越细耦合度越低,外观模式就是为了降低耦合度。
代理模式,代理者保存一个被代理的一个对象;适配器模式,保存了一个被适配的对象;而外观模式,就保存了各个子系统对象,然后根据实际逻辑组合。
14、责任链模式(关键代码:Handler 里面聚合它自己,在 HanleRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去)
Java代码例子好,url例子不好
15、命令模式(关键代码:定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口)
Java代码例子好,url例子不好
16、解释器模式(关键代码:构件环境类,包含解释器之外的一些全局信息,一般是 HashMap)
java中可以用expression4J替代
17、迭代器模式(应用实例:JAVA 中的 iterator)
18、中介者模式(关键代码:对象 Colleague 之间的通信封装到一个类中单独处理)
中心(各个类和中介者这个中心类有关联)
一般来说,同事类之间的关系是比较复杂的,多个同事类之间互相关联时,他们之间的关系会呈现为复杂的网状结构,这是一种过度耦合的架构,即不利于类的复用,也不稳定。例如有六个同事类对象,假如对象1发生变化,会有4个对象受到影响。如果对象2发生变化,那么会有5个对象受到影响。也就是说,同事类之间直接关联的设计是不好的。
如果引入中介者模式,那么同事类之间的关系将变为星型结构,任何一个类的变动,只会影响的类本身,以及中介者,这样就减小了系统的耦合。一个好的设计,必定不会把所有的对象关系处理逻辑封装在本类中,而是使用一个专门的类来管理那些不属于自己的行为。
19、观察者模式(关键代码:在抽象类里有一个 ArrayList 存放观察者们)
Java代码例子好,url例子不好
JAVA 中已经有了对观察者模式的支持类,观察者实现Observer接口,被观察者继承Observable类
20、状态模式(关键代码:通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if...else 等条件选择语句。)
对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为(重点理解)
使用场景: 1、行为随状态改变而改变的场景。 2、条件、分支语句的代替者
状态模式:
相当于If else if else;
设计路线:各个State类的内部实现(相当于If,else If内的条件)
执行时通过State调用Context方法来执行。
职责链模式:
相当于Swich case
;设计路线:客户设定,每个子类(case)的参数是下一个子类(case)。
使用时,向链的第一个子类的执行方法传递参数就可以。
有的人采用的是状态模式,从头到尾,提前一定定义好下一个处理的对象是谁,而我采用的是职责链模式,随时都有可能调整链的顺序。
这两个设计模式最大的区别就是状态模式是让各个状态对象自己知道其下一个处理的对象是谁,即在编译时便设定好了的。
21、空对象模式()
22、策略模式(关键代码:实现同一个接口)
策略模式:策略模式的客户端必须对所有的策略类相当了解,明确当前场景下各种策略的利弊,权衡在当前场景下应该使用哪种策略,也就是是说策略类对客户端是暴露的
状态模式:状态模式依赖于其状态的变化时其内部的行为发生变化,将动作委托到代表当前状态的对象,对外表现为类发生了变化。(重点理解)
23、模板模式(关键代码:通用与公共方法在抽象类实现,其他步骤在子类实现,为防止恶意操作,一般模板方法都加上 final 关键词)
24、访问者模式(关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。)
例子可以见https://blog.csdn.net/jason0539/article/details/45146271
假如一个对象中存在着一些与本对象不相干(或者关系较弱)的操作,为了避免这些操作污染这个对象,则可以使用访问者模式来把这些操作封装到访问者中去。
假如一组对象中,存在着相似的操作,为了避免出现大量重复的代码,也可以将这些重复的操作封装到访问者中去。