设计模式笔记

体现封装 继承 多态 类的关联 与 组合

类与类之间6种关系。 

关联

  一般关联

    单向  你中有我

    双向   双方各自持有对方类型的成员变量  (你中有我 我中有你)

    自关联  如链表 LinkList

  聚合  空心聚 A中传B 你死我活  弱关联         构造传入/set传入

  组合 实心组 A中newB 同生共死 强关联

 依赖关系  虚线

  一种使用关系,它是对象之间耦合度最弱的一种关联方式,是临时性的关联。

    在代码中,某个类的方法通过局部变量方法的参数或者对静态方法的调用来访问另一个类(被依赖类)中的某些方法来完成一些职责

继承

实现

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

SOLID原则  + 合成复用 + 迪米特

开闭原则是设计模式的第一大原则,它的潜台词是:控制需求变动风 险,缩小维护成本。(对扩展开放,对修改关闭)原类不动,创建新类(关联)

依赖倒置的潜台词是:面向抽象编程,解耦调用和被调用者。如果 A 中关联 B,那么尽量使得 B 实现某个接口,然后 A 与接口发生关系, 不与 B 实现类发生关联关系。

迪米特原则的潜台词是:不和陌生人说话,有事去中介。(类之间的直接联系尽量的少,两个类的访问,通过第 三个中介类来实现)

里氏替换  子类必须能替换基类(对继承的约束规范,子类别瞎改影响原有业务)保证继承复用是可靠的

接口隔离  最小接口

单一职责

合成复用

  尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
  通常类的复用分为继承复用合成复用两种。
  继承复用虽然有简单和易实现的优点,但它存在以下缺点:
    1.继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。
    2.子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于子类的扩展和维护。
    3.它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化
  采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:
    1.它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为"黑箱"复用。
    2.对象间的耦合度低。可以在类的成员位置声明抽象
    3.复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

分类

  对象的创建-6  对象的创建与使用分离

      简单工厂(不算GOF)、工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

  对象的组成-7 结构

      适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

    结构型模式描述如何 将类或对象 按某种布局 组成更大的结构。它分为类结构型模式和对象结构型模式,

    前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象

    由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型 模式具有更大的灵活性

  对象的行为-10 功能 + 1

      策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、 命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

简单工厂(static升级静态工厂)--一厂造所有 (违反开闭----有变原厂要动)

工厂方法-- 抽象工厂----->一类一厂---- 符合开闭-----------------一个接口生产一个产品-----一维数组

抽象工厂-----二维数组???  适合一族产品

    抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组 产品称为一个产品族,

    下图所示横轴是产品等级,也就是同一类产品;纵轴是产品族,也就是同一品牌 的产品,同一品牌的产品产自同一个工厂

image

   抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生 产多个等级的产品

  抽象/具体工厂生产一种商品,这里扩展成了生产一组不同种类的商品。

  一个接口生产多个产品

原本工厂只能生产一种商品,现在可以多种了-------------一族产品

 

枚举存储?枚举在编译期就必须定下来具体的值,你怎么做存储的?

工厂模式+ 反射读取配置文件

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

单例模式--内存中就一个对象-构造私有,变量私有-不给外人用,自己提供一个方法对外。

  饿汉2- Runtm类   静态变量、静态代码块

  懒汉4 --懒加载(线程安全) --------不安全-->重量及安全--轻量级安全(双重检索式)

    JVM在实例化对象的时候会进行优化和指令重排序操作。添加 volatile 关键字之后的双重检查锁模式是一种比较好 的单例实现模式,能够保证在多线程 的情况下线程安全也不会有性能问题

  静态内部类单例模式中实例由内部类创建,由于 JVM 在加载外部类的过程中, 是不会加载静态内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。静态属性由于被 static 修饰,保证只被实例化一次,并且严格保证实例化顺序

    1、外部类加载不会加载内部类(满足饿汉式)2、内部可以访问外部类的资源3、使用final修饰变量,可以起到线程安全的作用(只会分配一次)

      类的加载只会加载一次,所以不会有线程安全问题,和静态方法不一样

 

  枚举(饿汉式)--所用单例实现中唯一一种不会被破坏的单例实现模式

---

破坏单例 

  序列化  因为序列化读出来的对象是原来对象的拷贝!!!

  反射  强制调用私有的构造

要理解底层,反序列化和反射破化单例设计模式本质上是一个是绕过了构造方法,一个是取消了检查访问从而创建了对象,而enum类jvm

要理解实质,反序列化和反射一个是绕过构造方法,一个是修改了访问检查从而创建了对象,而enum类是jvm底层禁止通过反射和反序列化创建实例,这就是为啥反射和反序列化破坏单例,而enum安全

解决方案

  在Singleton类中添加readResolve()方法,在反序列化时被反射调用,如果定义了这个方法, 就返回这个方法的值,如果没有定义,则返回新new出来的对象。

if (obj != null && handles.lookupException(passHandle) == null && desc.hasReadResolveMethod()) {

image

image

反射解决:你跳过修饰符获取构造方法,那我就在构造方法里加逻辑,让你先判断,存在就抛异常

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

建造者模式-- 组合新对象。不能或不给直接new 原来多成员对象,而是通过构建者创建。构建者包含了原来对象的组成,支持一个一个分开构建。

  构建+组装-建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。

  构建者模式的Builder用于具体的部件的构造,最后用Director组装,适用于复杂对象一步一步的构建,而工厂模式强调的是不同的工厂实现不同的产品不需要知道其构建的步骤

看到这里感觉,是将抽象工厂中的工厂类中对象的创建,分为这里的 Builder 类 和 Director 类

指挥者里只关心我组装过程有哪几个流程,至于具体你各个流程要进行的处理,我这里并不关心,相当于建造过程和表示分离开了

模板方法组合工厂。这和模板方法有什么区别

相对于工厂模式,可以对某个部件进行扩展

  产品类---》建造产品类(实现抽象 builder 类,一个一个给产品类的组件具体赋值)---》指挥建造产品类(传入具体建造产品类)生产

======指挥建造产品类(传入具体建造产品类)生产 直接合并到 抽象建造类里

应用-链式编程。

image

 原始构建者顺序 由指挥者定义。现在由客户自定义、

@Builder

mybatisplus 很多都是这种

=======================>  一个复杂对象,在旁边搞个构建者,一个一个赋值,最后builde();

 

 

工厂方法模式注重的是整体对象的创建方式;而建造者模式注重的是部件构建的过程,意在通过一步一 步地精确构造创建出一个复杂的对象。

抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组 合,采用抽象工厂模式则是不需要关心构建过程,只关心什么产品由什么工厂生产即可。

建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。

 

模板设计

  抽象类里定规矩,方法里套抽象方法,子孙实现抽象方法。

 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

原型模式:原型 implements Cloneable, 序列化

  克隆模式 super.clone()

   浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

   深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。----- 对象流 序列化反序列化

 因为所有类的超类 Object 已实现方法 clone,Cloneable 是标记接口 ,确实是object中的clone,接口是空的 !?

object里面是native,是调用底层C++代码,没有空

原型对象和克隆对象中的引用对象,是同一个对象

克隆了一个新对象,指向的是原对象指向的地址

也就是说浅克隆会创建一个新的克隆对象,和原来的原型对象的内存地址并不相同。但是对于对象的属性,如果是引用类型,克隆对象和原型对象公用一个内存地址的成员属性。

如果在克隆对象中修改引用类型的属性,那么原型对象中对应的引用类型属性的值也会更改。

 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

接口定规范-多态,抽象定规则-成员聚合,方法算法 ??

 

 单例

   构造私有-- 但是反射可以获取

 类加载的时候,动态的成员变量和方法是在调用的时候才加载

饿汉式

  静态变量

  静态代码块

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

IO流--装饰模式: -- 继承的替代方案。动态增加,随意聚合(-A中传B

new BufferedReader(new InputStreamReader(System.in));-- 两层装饰

缓冲(字符(字节); 

new Scanner(System.in); -- 一层装饰

 

 

代码结构和静态代理基本一样。真实对象不由客户端调用的,肯定是静态代理。装饰模式绝对由客户端调用。

解决类爆炸问题???

由extends的顺位继承功能增强,到扶持宗族的包装组合.。装饰模式,突出的是运行期增加行为,这和继承是不同的,继承是在编译期 增加行为。

装饰类和目标类,都是同一个接口,但是装饰类把目标类构造进入自己类里,增强功能!

image

动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点, 继承的功能是静态的,不能动态增删。)

image

装饰者 可以灵活组合,一直套娃!叠加增强。客户端决定如何装饰-当面组装。

如果某个装饰类增加对外扩展方法,会破坏装饰器的透明性。因为如果有多层装饰,上层可能无法访问这个设置

静态代理(组合-A中newB只一层代理,但可以扩展接口-对外提供管理用方法,是因为代理不仅仅是接口的传递者,更是一个完整的管理者。

它负责控制对真实对象的访问,因此需要一些管理方法来配置和控制这个访问过程。
而装饰器模式的纯粹目的是功能叠加,保持接口一致性能让装饰器透明地嵌套使用。

注意:代理模式下,客户端通常不直接访问真实对象,真实对象对客户端是隐藏的。装饰者对客户端是显示的,客户端决定如何装饰。

image

代理模式 - 代理控制对象的创建和生命周期,代理决定何时创建真实对象,"代表"和"控制",重点在"控制",代理决定是否/何时调用真实对象
装饰器模式 - 客户端创建并传递被装饰对象.-多层嵌套是核心特性,重点在"增强",透明地添加功能,不控制对象的生命周期

代理模式:代理类自己new真实对象,客户端只new代理。代理模式,是类之间的封装和(某方面的)复用。
装饰类自己不创建,只是接收,外部传入,装饰器不new
体现了控制权的归属,代理控制真实对象的创建和生命周期
代理负责管理增强,装饰器负责只增强。

image

 

image

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

适配器设计模式---- 客户端期望的一个接口,其方法,突然想起来,现在正好有其他一个类的一个方法正合适,但是两者没关系。

--让他们有关系。 目标接口,目标类(有目标方法),适配类 继承目标接口+实现目标接口,目标方法嵌在接口方法里。-- 类适配器

image

不继承改聚合,就是 对象适配器

image

接口适配器- 抽象类空实现所有方法。-- 匿名内部类选择一个实现。

image

 

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

posted on 2022-01-24 21:12  daofree  阅读(36)  评论(0)    收藏  举报