GOF
工厂模式
简单工厂
一个抽象产品类派生出多个具体的产品类,但是一个工厂就生产了全部的产品
- 简单工厂在创建对象的时候不需要具体的逻辑,只要用户的一个标识就可以获取对应的产品。
- 例子:图形,圆形,矩形,工厂
- 优点:每次增加一个产品类只需要增加一个实现类即可(实现产品接口
- 缺点:如果添加一个产品类,那么我们就需要在工厂类中添加对应的代码(违反开闭原则)
工厂方法
有一个抽象工厂派生出多个具体的工厂,每个工厂生产一件具体的产品
每个具体的产品类都有一个具体的工厂类生产
优点:
- 易于扩展,如果需要添加一个产品类,只需要添加一个具体的产品类和对应的工厂类即可,不需要对原工厂的方法进行任何的修改
- 在工厂方法模式中,用户只需要知道所需要产品的具体工厂类即可,不需要知道具体的创建过程,甚至不需要知道具体产品类的类名。
缺点:
- 每次新增一个产品时,都需要增加一个具体的产品类和具体的工厂类,明显的成倍增加代码。
抽象工厂
多个抽象产品类,派生出多个具体产品类;一个抽象工厂类,派生出多个具体工厂类;每个具体工厂类可创建读个具体产品类实例。
这里的抽象产品类就像是一类产品的族,其中具体实现类就是不同的表现形式而已。
这里的每一个具体的工厂类可以生产不同种类的产品,并不是一个具体的工厂类只能生产一个具体的产品罢了
总结:
- 抽象工厂模式一个一个工厂生产一个产品类族
- 其中的工厂并不是生产一种产品,而是生产多种产品(一类的产品)
例子:小米手机,小米路由器,华为手机,华为路由器,一个小米工厂实现抽象工厂,生产小米系列产品!!!!!!
学习地址:https://zhuanlan.zhihu.com/p/35605204
单例模式
懒汉式
什么是懒汉式?
顾名思义懒,需要调用getInstance()方法去获取单例对象,当需要创建的时候,才去调用方法创建
- 节省资源
- 线程不安全(当多个线程同时进入方法时,导致创建多个对象,这样就不是单例了)
解决线程不安全:
1.使用线程同步锁(synchronized) —同步方法
2.双重校验是当前对象否为null(也就是是否已经被创建了),-----同步代码块
3.匿名内部类 (推荐使用)
饿汉式
什么是饿汉式?
顾名思义,饿就是需要吃东西,所以类加载的时候就会创建单例对象了,而不是在getInstance()方法里面进行调用了
利用静态成员变量或者静态代码块进行对象的初始化
- 线程安全
- 当初始化没有被使用的时候,则存在浪费资源
总结
- 饿汉式在类加载的时候就会创建单例对象,因此浪费资源
- 懒汉式在用到的时候才创建,节省资源,但是线程不安全,但是我们可以使用匿名内部类的方式使其线程安全
- 一般在使用的时候会使用懒汉式的匿名内部类的实现和饿汉式的创建方式
学习地址:https://zhuanlan.zhihu.com/p/35635356
原型模式
什么是原型模式?
用于创建重复的对象,提供了一种创建对象的最佳方式。
分为深克隆和浅克隆
为什么需要这个模式呢?
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
浅克隆:
需要实现cloneable接口(表示java支持被复制,否则报错),然后调用object的clone方法
- 如果克隆的原型对象的成员变量是基本数据类型(值类型)的话,则克隆成功
- 如果克隆的原型对象的成员变量是引用类型的话,则复制的是原型对象的地址,当原型对象改变的话,克隆对象也会改变
例子:周报,附件
深度克隆:
可以完成复制引用类型和值类型
原理:通过序列化的方式来实现,序列化是将兑现表写到流中去,写到流中的对象是原有对象的一个拷贝,而原对象依然存在内存当中
通过是序列化实现的拷贝可以实现原型对象本身的拷贝,还可以实现原型对象的成员变量引用类型的拷贝
操作:
1.先创建一个字节数组输出流
2.进行装饰模式,使用对象输出流进行包装,然后将对象写入输出流中
3.创建一个字节输出的输入流
4.进行装饰模式,将字节数组输出流传入到字节数组的输入流中
5.在使用装饰模式,将对象输入流进行包装字节数组输入流
6.最后调用将对象从输出流中读出
学习地址:https://zhuanlan.zhihu.com/p/35698574
建造者模式
什么是建造者模式?
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
- 建造者的功能就是先构造复杂对象的每一个部件,
- 指挥者的功能就是将这些部件以一定的步骤组装起来,形成一个具有一定功能的产品或者对象。当然这个步骤是透明的对于客户端。
例子:
组件:轮胎,引擎
产品:汽车(包含轮胎,引擎,聚合关系-成员变量)
抽象构造者:接口,定义了轮胎,引擎的实现方法
详细构造者:实现接口,实现真正的轮胎,引擎
指挥者接口:定义实现产品的接口
指挥者实现类:实现接口,传入构建者,进行自己构建组件的顺序,然后返回产品
场景:
基本部件不变,但是其中的组合经常变化的情况
- 比如你去肯德基点餐,汉堡,可乐,鸡翅这些食物是不变的,但是套餐的组合是经常变化的,建造者模式的指挥者就是将这些部件按照一定步骤将其组合起来的。
- java中StringBuilde
需要生成的对象具有复杂的内部结构
- 复杂的内部结构,我们可以使用建造者模式将其分离,先将其中的各个小的部件组装成功,然后由指挥者按照一定的步骤将其组装成一个复杂的对象
学习地址:https://zhuanlan.zhihu.com/p/356876857
代理模式
什么是代理模式?
因为某些原因,客户不想要直接访问对象,这时候就需要一个代理对象去帮助客户完成功能。—Spring中的面向切换编程就是这个原理
- 当使用代理对象时,真实类中的信息对客户来说是透明的
- 用于对象的间接访问提供了一个方案,可以对对象的访问进行控制
静态代理:
每次代理对象,都写一个新的代理类,麻烦
动态代理:
jdk的动态代理,(当类要实现接口时使用)
实现InvocationHandler接口,编写方法调用时的前后方法嵌入操作
生产代理类poxy(根据当前类加载器,实现的接口的字节码文件,真实类(实现类))
cglib动态代理进行实现 (当类要继承方法的时候使用)
好处:即使有多个接口,也仅仅只有一个动态代理类
学习地址:https://zhuanlan.zhihu.com/p/35701594
适配器模式
什么是适配器模式?
将一个接口转化成客户想要的另一个接口,使接口不兼容的那些类可以一起工作
例子:
类适配器:适配器类继承适配者对象 ---- 不提倡使用
目标接口:5v电压
适配者类:220v的电压的类
适配器类:将220v的电压转化为5v
产品类:笔记本对象吗,传入5v的接口对象,进行充电
对象适配器:适配者对象作为适配器类的成员变量 ----组合方式,提倡使用
桥接模式
什么是桥接模式?
如果软件系统中某个类存在两个独立变化的维度,通过该模式可以将这两个维度分离出来,使两者可以独立扩展,让系统更加符合“单一职责原
原理:
桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联取代了传统的多层继承,将类之间的静态继承关系转换为动态的对象组合关系,使得系统更加灵活,并易于扩展,同时有效控制了系统中类的个数
例子:
-
因为一个电脑需要继承不同类型电脑的抽象类,以及继承产品的类(实现产品接口)
当我们在增加一个产品华为时,需要增加三个类!!!!
-
可是当我们将抽象类与真实产品类进行抽离的话,作为成员变量的关系,品牌为电脑的成员变量(通过构造器进行初始化)
这样我们就只需要写一个类了!!!!!
使用场景:
- 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
- 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
- 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
总结:
- 扩展性很强,如果想要添加一个电脑的种类或者添加一个品牌,只需要添加一个具体的实现类即可。并不需要成倍的添加。
- 将多层继承用了组合的方式实现了,即是品牌类作为电脑的一个成员变量,那么就可以实现电脑拥有多种品牌
学习地址:https://zhuanlan.zhihu.com/p/35756273
设计模式之关系
继承和泛化
泛化关系是一种继承关系,表示一般与特殊的关系,它指定了子类如何特化父类的所有特征和行为。
接口与实现
一个类只能继承一个父类,但是可以实现多个接口
依赖
是一种使用关系,即一个类的实现需要另外一个类的协助,所以尽量不使用双向的依赖关系。
学习地址:https://zhuanlan.zhihu.com/p/35635280