设计模式--创建型模式,期末必考!工厂模式的开闭原则和单例模式的创建方式和特点

三种工厂模式关于开闭原则的实现

先了解什么是OCP,一个类可以允许拓展它的功能,而不允许修改它的源码

别着急觉得读懂了,暂且保证什么叫扩展,也就是无论继承还是关联关系的在这个系统增加类去增加方法,而不是试图去改原有的类与代码

如果你很熟悉工厂模式,那么我想分享这句话,工厂模式的定义:

        在基类中定义创建对象的一个接口,让子类决定实例化哪个类。工厂方法让一个类的实例化延迟到子类中进行。

重点在于,我们可以将对象的创建和使用分离,避免实例化一个类的数据和代码在多个类中到处都是。

开闭原则的题目

        主要是这样考察:你了解三种工厂模式吗?聊聊他们之间的相同与不同处,说说他们如何实现开闭原则。

  • 相同在于
    • 三种工厂模式都隔离了对象的创建和使用,客户端只需要关系使用产品,而生产产品的过程交给了工厂类
    • 都封装了抽象产品类
  • 不同在于
    • 简单工厂把所有的产品类型都放在一个工厂中,这导致如果需要生产一个新的产品,就不得不回到工厂类的代码中,增添方法,这违背了开闭原则。
    • 工厂模式和抽象工厂模式都提供了抽象工厂角色,让具体工厂继承与抽象工厂以实现对产品的创建。但是工厂模式和简单工厂模式是对应一个产品等级结构(单类产品)的,而抽象工厂则是对应多个产品等级结构(形成产品族)的。(记得举例说明的汽水和玩偶吗)
  • 专注于开闭原则
    • 只有工厂模式真正意义的实现开闭原则
    • 简单工厂因为把所有的产品生产都放入一个工厂类,导致新产品不得不修改唯一工厂类的源代码
    • 抽象工厂模式则是因为在产品族的定义上,导致抽象工厂模式的扩展有一定的“开闭原则”倾斜性。
      • 抽象工厂认为一个品牌是产品的父亲,也就是把所有该品牌下的产品都归于一个工厂类,那么当我们的需求是新增一个新品牌时,只需要新建一个新品牌的工厂,并完整代码即可,这符合OCP。
      • 而当该品牌需要一个新的产品的时候,又发生了和简单工厂一样的情况,不得不回到该品牌工厂内新增或修改源码,这不符合OCP

特殊回答的总结

  • 系统中只存在一个等级结构的产品时,抽象工厂模式退化工厂方法模式
  • 抽象工厂模式就是对简单工厂模式的进一步抽象(这也导致了他们因为同样的问题发生违法OCP的情况)

单例模式的实现

先知道什么是单例,就是这个类自身创建了自己这个对象并且持续维护唯一一个and提供方法供其他类使用。注意这里已经描写了它的三个特点:创建自身(new),全局唯一,提供方法(getInstance)

实现要点

  1. 构造器(构造函数)私有
  2. 含有一个该类的静态变量来保存这个唯一的实例
  3. 对外提供获取该实例对象的方法

饿汉式

        所谓饿汉就是无论要不要,他都很急,所以不论是否需要这个对象都直接new创建并维护

public class M01 {
    //这一行
    private static final M01 INSTANCE = new M01();
    private M01(){}
    public static M01 getInstance(){
        return INSTANCE;
    }
}

优点:

避免了线程同步问题,不存在线程安全问题

缺点:

在类加载的时候就完成了实例化,如果从未使用过该类,造成内存浪费

懒汉式

一个吃饱的人就比较懒,也就是懒加载

当需要的时候再创建对象

public class M03 {
    private static M03 INSTANCE;
    private M03(){}
    public static M03 getInstance(){
        //判断当前不存在一个实例再new
        if(INSTANCE == null){
            INSTANCE = new M03();
        }
        return INSTANCE;
    }
}

 在多线程的情况下,线程不安全

public static void main(String[] args) {
        for(int i = 0;i<100;i++){
            new Thread(()->{
                System.out.println(M03.getInstance().hashCode());
            }).start();
        }
    }

一百个线程一起跑,可能出现a和b两个线程同时读取到if(INSTANCE == null)这句话,都认为当前空间下,不存在实例,都新建了一个实例对象。这时候就不满足唯一实例对象的要求了。

优点:

        节省空间

缺点:

        线程不安全,题目肯定会要求你说出为什么不安全,请按照上面多线程的分析回答该问题

DCL双重检查

public class M06 {
    private static M06 INSTANCE;
    private M06(){}
    public static M06 volatile getInstance() {
        if (INSTANCE == null) {
            //当发现空间内不存在实例对象,先锁住当前类
            synchronized (M06.class) {
            //避免两个进程同时获取到锁
            //则当前线程再判断一次是否不存在对象
                if(INSTANCE==null){
                    INSTANCE = new M06();
                }
            }
        }
        return INSTANCE;
    }
}

        基本解决线程不安全和内存空间浪费的问题 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值