大乱炖-设计模式

不记文档,白忙一场


0、概述

学习地址

1> 学习地址一
    地址:菜鸟教程 -> 工厂模式
    网址:https://www.runoob.com/design-pattern/factory-pattern.html

分类

总体来说设计模式分为三大类:
​
1> 创建型模式,共五种:工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式。
2> 结构型模式,共七种:适配器模式、桥接模式、代理模式、组合模式、装饰器模式、外观模式、享元模式。
3> 行为型模式,共十一种:观察者模式、访问者模式、中介者模式、解释器模式、迭代器模式、备忘录模式、策
    略模式、命令模式、状态模式 <模板方法模式、责任链模式>。

1、工厂模式

工厂/抽象工厂区别

经典:
    https://m.php.cn/article/344745.html

应用场景

1> 场景:
    通过使用一个共同的接口来指向新创建的对象(不暴露创建逻辑)
-------------------------------------------------------------------------------------------
2> 例子:
    统一接口创建不同"形状接口"实现类的对象
-------------------------------------------------------------------------------------------
3> 最终实现:
    1> 一个抽象工厂类,可以派生出多个具体工厂类(一致)。 
    2> 一个抽象产品类,可以派生出多个具体产品类。   
    3> 一个具体工厂类,只能创建一个具体产品类的实例。
-------------------------------------------------------------------------------------------
注:
    1> 工厂类和抽象工厂类区别:
        1) 抽象工厂模式,就是将多个工厂类又抽象出来一个超级工厂类(当然多个工厂类是相关联的)
        2) 工厂模式:"圆"有一个工厂类,"矩形"有一个工厂类,"正方形"有一个工厂类
    2> 解决简单工厂模式问题:创建一个工厂接口和创建多个工厂实现类
    3> 简单工厂模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行
        修改,这违背了闭包原则。

2、抽象工厂模式

应用场景

1> 场景:
    一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂
-------------------------------------------------------------------------------------------
2>例子:
    一个"图形"既有"形状"又有"颜色",这两个属性分别有多个实现类需要用工厂来创建
-------------------------------------------------------------------------------------------
3> 最终实现:
    1> 一个抽象工厂类,可以派生出多个具体工厂类(一致)。
    2> 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。   
    3> 一个具体工厂类,可以创建多个具体产品类的实例。
-------------------------------------------------------------------------------------------
注:
    1> 抽象工厂模式,就是将多个工厂类又抽象出来一个超级工厂类(当然多个工厂类是相关联的)
    2> 工厂模式:"圆"有一个工厂类,"矩形"有一个工厂类,"正方形"有一个工厂类

3、单例模式

应用场景

1> 场景:
    一个类负责创建自己的对象,同时确保只有单个对象被创建
-------------------------------------------------------------------------------------------
2>例子:
    宇信eChain框架中,WorkflowCache类对象单例,且只有第一次访问创建一次
-------------------------------------------------------------------------------------------
3> 最终实现:
    1> 变量:静态的(内存中只有一份),私有(防止外部通过类.变量名调用)、final(可有可无)
    2> 构造器:私有(阻止外部直接实例化对象)
    3> 方法:公有(供外部调用)
-------------------------------------------------------------------------------------------
注:
    1> 饱汉(懒汉),用的时候才实例化对象;饥汉,不管用不用先实例化出来
    2> 饱汉模式,注意getInstance方法中创建对象new包括外面判断instance是否为null,需要加锁
    3> 创建单例模式的所有方法:懒汉式、饿汉式、双重校验锁、静态内部类、枚举
    4> 懒汉式:有线程安全和不安全两种写法
    5> 懒汉式 vs 双重校验锁:一切为了性能,懒汉式锁方法,双重校验锁锁代码块,性能更高
    6> 饥汉式:基于classloader 机制
    7> 静态内部类:基于classloader 机制
-------------------------------------------------------------------------------------------
注:
    1> 双重校验锁解释:https://blog.csdn.net/java_1996/article/details/87472644
    2> volatile修饰的变量不允许"指令重排序",确保所有线程看到这个变量的值是一致的
    3> Test类中有Test t = new Test()成员变量,会stackOverflowError
    4> Test类中有static Test t = new Test()静态成员变量,则正常创建
    5> 对静态域使用延迟初始化,应使用静态内部类(因为更简单,且"静态内部类"只适用于静态域的情
        况);
        双检锁方式可在实例域需要延迟初始化时使用。
    6> 饥汉式:它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例
        化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不
        能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到
        lazy loading 的效果。
    7> classloader 机制:
    8> 静态域 vs 实例域:
-------------------------------------------------------------------------------------------
注:双重校验锁
    1> 执行双重检查是因为,如果多个线程同时了通过了第一次检查,并且其中一个线程首先通过了第二次检查
        并实例化了对象,那么剩余通过了第一次检查的线程就不会再去实例化对象。
    2> 这样,除了初始化的时候会出现加锁的情况,后续的所有调用都会避免加锁而直接返回,解决了性能消耗
        的问题。
    来源:https://www.cnblogs.com/xz816111/p/8470048.html
    3> 第二层校验是否为null的必要性
        1> 如果a、b两个线程同时执行完外层if (singleton == null) 的判断
        2> 都卡在synchronized (Singleton.class)锁的地方
        3> 如果没有内层if (singleton == null) 的判断,线程a先获得锁,执行了初始化实例,释放锁
        4> 线程b会获得锁,在内部再次执行初始化实例
        总结:所以内外两层if (singleton == null) 的判断都是有必要的,第二次之后只会经过外层判断
    4> volitile的必要性
        给类对象赋值的过程,分为3步:
            1> 给singleton分配内存;
            2> 调用 Singleton 的构造函数来初始化成员变量;
            3> 将给singleton对象指向分配的内存空间(此时singleton才不为null)
        而JVM的指令会重排序,如果线程a正在进行对象赋值,
        线程b进行外层if (singleton == null) 的判断,而指令重排序使得给变量分配完空间后,直接执行
        步骤3,将没有初始化的singleton对象指向分配的内存空间,则变量为null
        那么步骤3执行后singleton已经不为null,但是未执行步骤2,singleton对象初始化不完全,此时线
        程B执行getInstance()方法,第一步判断时singleton不为null,则直接将未完全初始化的
        singleton对象返回了
        来源:https://blog.csdn.net/java_1996/article/details/87472644
-------------------------------------------------------------------------------------------
注:触发类加载的情形
    1> 显示加载:直接使用类的加载器进行加载.
    2> 隐式加载:
        1> 构建类的对象(包括new对象、反射创建对象)
        2> 访问类的成员(静态成员变量,静态成员方法)

4、建造者模式

应用场景

场景:使用多个简单的对象一步一步(一层套一层)构建成一个复杂的对象。
解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,该对象后期可能经常变动
-------------------------------------------------------------------------------------------
例子:
1、肯德基点套餐,这个套餐是:一个汉堡(Burger)和一杯冷饮(Cold drink)
2、汉堡(Burger)可以是素食汉堡(Veg Burger)或鸡肉汉堡(Chicken Burger),它们是包在纸盒中。
3、冷饮(Cold drink)可以是可口可乐(coke)或百事可乐(pepsi),它们是装在瓶子中
-------------------------------------------------------------------------------------------
最终实现:
1、抽象最上层接口("物品接口"):包括 - 名称、包装、价格
    注:因为包装还需要抽象,所以写代码时候,需要先抽象"包装接口"
2、其中物品接口的包装属性,可以抽象接口("包装接口")
3、"包装接口"两个实现类:纸质包装和瓶子包装
4、"物品接口"有两个抽象类的实现类:汉堡和冷饮(所有汉堡的包装属性一样,固定下来,继承就好。冷饮同      理)
5、具体"物品实现类":
    蔬菜汉堡 - 继承汉堡抽象类,重写名称和价格方法
    鸡肉汉堡 - 继承汉堡抽象类,重写名称和价格方法
    可口可乐 - 继承冷饮抽象类,重写名称和价格方法
    百事可乐 - 继承冷饮抽象类,重写名称和价格方法
6、创建一个"套餐类"
    成员变量,是整合套餐中的"物品接口"对象
7、创建一个"创造者类"
    内部方法,就是返回"套餐类"对象
-------------------------------------------------------------------------------------------
注:
    一层套一层
    "包装接口"(瓶子和纸盒) -> "食品接口"(汉堡<蔬菜和鸡肉汉堡>和冷饮<可口和百世>) -> "套餐类"

5、原型模式

应用场景

场景:
    用于创建重复的对象,同时又能保证性能
-------------------------------------------------------------------------------------------
例子:
    创建一个对象,需要连接数据库,耗费大量资源的时候
-------------------------------------------------------------------------------------------
最终实现:
    1> 抽象类,实现cloneable接口,重写clone方法。
    2> 提前加载数据进行存储。
    3> 需要创建重复对象时,从存储中拿到再调用clone方法
-------------------------------------------------------------------------------------------
注:
    与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值