博客信息

常见得几种设计模式

0
发布时间:『 2020-05-11 16:32』  博客类别:设计模式  阅读(80) 评论(0)

单例模式:

单例模式的应用场景

单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并 提供一个全局访问点。单例模式是创建型模式。单例模式在现实生活中应用也非常广泛。 例如,国家主席、公司 CEO、部门经理等。在 J2EE 标准中,ServletContext、 ServletContextConfig 等;在 Spring 框架应用中 ApplicationContext;数据库的连接 池也都是单例形式。

饿汉式:静态类中已经new出来的对象,通过方法返回

懒汉式:静态类中没new,方法里面判断new new,newnew一下,new过的 就返回

静态内部类:获取方法里面返回的是静态内部类中的对象

序列化单例:通过序列化调用重写回调得到的单例

PS:静态就能保证线程同步安全,饿汉式最快

饿汉式单例

先来看单例模式的类结构图: 饿汉式单例是在类加载的时候就立即初始化,并且创建单例对象。绝对线程安全,在线 程还没出现以前就是实例化了,不可能存在访问安全问题。

优点:没有加任何的锁、执行效率比较高,在用户体验上来说,比懒汉式更好。

缺点:类加载的时候就初始化,不管用与不用都占着空间,浪费了内存,有可能占着茅 坑不拉屎。 Spring 中 IOC 容器 ApplicationContext 本身就是典型的饿汉式单例。接下来看一段代 码:

这两种写法都非常的简单,也非常好理解,饿汉式适用在单例对象较少的情况。下面我 们来看性能更优的写法。

懒汉式单例

懒汉式单例的特点是:被外部类调用的时候内部类才会加载,下面看懒汉式单例的简单 实现 LazySimpleSingleton:

双重锁单例

牺牲部分性能换取安全性。synchronized 关键字在jdk1.6以后已经优化很多,但是还是存在性能损耗。

内部类单例

这种形式兼顾饿汉式的内存浪费,也兼顾 synchronized 性能问题。内部类一定是要在方 法调用之前初始化,巧妙地避免了线程安全问题。

反射破坏单例

基于上面内部类单例来执行,单例构造方法是私有时,通过反射依旧能创建单例。

所以我们需要在构造方法里面添加条件判断,判断当前对象不为空的时候,创建对象失败,丢异常返回、

序列化破坏单例

当我们将一个单例对象创建好,有时候需要将对象序列化然后写入到磁盘,下次使用时 再从磁盘中读取到对象,反序列化转化为内存对象。反序列化后的对象会重新分配内存, 即重新创建。那如果序列化的目标的对象为单例对象,就违背了单例模式的初衷,相当 于破坏了单例,来看一段代码:

测试代码:

运行结果是false,可以看出,反序列化后的对象和手动创建的对象是不一致的,实例化了两 次,违背了单例的设计初衷。那么,我们如何保证序列化的情况下也能够实现单例?其 实很简单,只需要增加 readResolve()方法即可。

如图:

注册式单例:枚举

ThreadLocal 线程单例

讲讲线程单例实现 ThreadLocal。ThreadLocal 不能保证其 创建的对象是全局唯一,但是能保证在单个线程中是唯一的,天生的线程安全。

在主线程 main 中无论调用多少次,获取到的实例都是同一个,都在两个子线程中分别获取到了不同的实例。那么 ThreadLocal 是如果实现这样的效果的呢?我们知 道上面的单例模式为了达到线程安全的目的,给方法上锁,以时间换空间。

ThreadLocal 将所有的对象全部放在 ThreadLocalMap 中,为每个线程都提供一个对象,实际上是以 空间换时间来实现线程间隔离的。

单例模式小结

单例模式可以保证内存里只有一个实例,减少了内存开销;可以避免对资源的多重占用。 单例模式看起来非常简单,实现起来其实也非常简单。


抽象工厂模式

抽象工厂模式(Abastract Factory Pattern)是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。

1.创建IAbstractFactory接口或抽象类作为具体工厂,ICourse,INote,IView接口做子工厂

2.实现IAbstractFactory的接口/抽象类,创建 Java 产品族和python产品族,然后在具体工厂里引用对应产品子工厂的行为方法调用。

原理:撸一个抽象类或接口的工厂类做具体工厂,里面方法调用后,获取多个不同的子工厂(接口)的生产结果(方法返回值)。


适配器模式:

将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作

写两个接口,通常新的接口适配旧的接口,然后把旧接口的类通过继承或者传递的方式 传到新接口(适配器)上, 得到旧接口数据然后实现新接口。


装饰模式:

1、用于扩展一个类的功能或给一个类添加附加职责。

2、动态的给一个对象添加功能,这些功能可以再动态的撤销。

写一个抽象方法BattercakeDecorator 装饰类继承Battercake,在装饰类里声明父类的引用,其中doSomething方法是自定义新增的,可以做新增的任何需求,其他方法重写引用父类的方法(也可以在原有方法上加扩展逻辑)。


策略模式:

定义一个抽象类/接口,拥有不同的业务实现,在弄一个策略的类,根据不同业务执行策略类去调抽象类/接口的对应实现类,就是策略模式。


委派模式:

根据任务安排不同的人干对应的活。

boos委派leader干一个任务,leader把这个任务把员工a或b去执行,这就是委派。




原型模式:

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

主要解决:在运行期建立和删除原型。

浅拷贝:通过implements Cloneable然后调用里面的clone拷贝方法

深拷贝:通过implements Cloneable, Serializable然后调用里面的clone拷贝方法

注意:序列化回来就不再是相同对象

何时使用: 

1、当一个系统应该独立于它的产品创建,构成和表示时。

2、当要实例化的类是在运行时刻指定时,例如,通过动态装载。

3、为了避免创建一个与产品类层次平行的工厂类层次时。

4、当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。

关键代码:

 1、实现克隆操作,在 JAVA 继承 Cloneable,重写 clone(),在 .NET 中可以使用 Object 类的 MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。

2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口。

应用实例: 

1、细胞分裂。

2、JAVA 中的 Object clone() 方法。

优点: 1、性能提高。 2、逃避构造函数的约束。

缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。

使用场景:

 1、资源优化场景。

2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。

3、性能和安全要求的场景。

4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。

5、一个对象多个修改者的场景。

6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。

7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。

注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。



动态代理:

静态代理:

类似传对象,然后自己实现前后处理逻辑,用自己创建对象(实现代理对象)来调用。

Jdk动态代理:

通过JDKnewProxy方法,被代理的对象要实现InvocationHandler接口,调用Invoke方法进行处理。


总结:静态代理是需要自己去实现代理对象和方法,而动态不需要。


关键字:   无
博主信息

勿扰
简介:对自己狠一点,社会才会对你好一点!
4年1月
QQ
热门文章
Powered by 勿扰 V2.0 湘ICP备18002237号-2     Copyright © 2016-2018 勿扰个人博客 版权所有