后段基础_12 | 青训营笔记

84 阅读13分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 14 天

一.简述

模式

创建型模式:

这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

  • 工厂模式(Factory Pattern)
  • 抽象工厂模式(Abstract Factory Pattern)
  • 单例模式(Singleton Pattern)
  • 建造者模式(Builder Pattern)
  • 原型模式(Prototype Pattern)

结构型模式:

这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。

  • 适配器模式(Adapter Pattern)
  • 桥接模式(Bridge Pattern)
  • 过滤器模式(Filter、Criteria Pattern)
  • 组合模式(Composite Pattern)
  • 装饰器模式(Decorator Pattern)
  • 外观模式(Facade Pattern)
  • 享元模式(Flyweight Pattern)
  • 代理模式(Proxy Pattern)

行为型模式:

  • 责任链模式(Chain of Responsibility Pattern)
  • 命令模式(Command Pattern)
  • 解释器模式(Interpreter Pattern)
  • 迭代器模式(Iterator Pattern)
  • 中介者模式(Mediator Pattern)
  • 备忘录模式(Memento Pattern)
  • 观察者模式(Observer Pattern)
  • 状态模式(State Pattern)
  • 空对象模式(Null Object Pattern)
  • 策略模式(Strategy Pattern)
  • 模板模式(Template Pattern)
  • 访问者模式(Visitor Pattern)

J2EE 模式:

这些设计模式特别关注表示层。这些模式是由 Sun Java Center 鉴定的。

  • MVC 模式(MVC Pattern)
  • 业务代表模式(Business Delegate Pattern)
  • 组合实体模式(Composite Entity Pattern)
  • 数据访问对象模式(Data Access Object Pattern)
  • 前端控制器模式(Front Controller Pattern)
  • 拦截过滤器模式(Intercepting Filter Pattern)
  • 服务定位器模式(Service Locator Pattern)
  • 传输对象模式(Transfer Object Pattern)

六大原则

1、开闭原则(Open Close Principle)

对扩展开放,对修改关闭。定义抽象类和接口。直接实现取改变。不改变原有的类。

2、里氏代换原则(Liskov Substitution Principle)

将功能抽象给接口。子类重写父类的方法,在父类和子类使用该方法时,会出现问题。

3、依赖倒转原则(Dependence Inversion Principle)

针对接口编程,依赖于抽象而不依赖于具体。这个原则是开闭原则的基础。

4、接口隔离原则(Interface Segregation Principle)

使用多个隔离的接口,比使用单个接口要好。不同的类只想用接口的一个方法,而不是全部方法,把这个方法抽象出去。

5、迪米特法则,又称最少知道原则(Demeter Principle)

一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。通过中介沟通。

6、合成复用原则(Composite Reuse Principle)

尽量使用合成/聚合的方式,而不是使用继承。

继承会导致代码臃肿,将每个子类都有的属性或者功能抽象出去。

二.四大模式

创建者模式

1.单例模式

这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

两种模式实现创建者模式:

  • 饿汉式:在类加载的时候就会创建对象实例
    • 通过私有属性、在类中静态创造实例、并创建一个静态创建该类的方法。
public class Singleton {
    private String name;

    private static Singleton singleton = new Singleton();

    public static Singleton getInstance(){
        return singleton;
    }
}
    • 通过静态代码块创建。可以在静态代码块中创建逻辑等方法
public class Singleton {
    private Singleton(){};

    private static Singleton singleton;

    static {
        singleton = new Singleton();
    }
    public static Singleton getInstance(){
        return singleton;
    }
}
  • 懒汉式:类加载不会导致单例被创建,只有首次使用该对象时才会被创建。线程不安全
// 通过加锁解决多线程创建多个对象的问题
public class Singleton {
    private Singleton(){};

    private static Singleton singleton;

    public static synchronized Singleton getInstance(){
        if (singleton == null) singleton = new Singleton();
        return  singleton;
    }
}
    • 双重检查锁模式。多线程模式下可能会出现空指针问题。添加 volatile 可以解决
public class Singleton {
    private Singleton(){};

    private static volatile Singleton singleton;

    public static Singleton getInstance(){
        // 该对象只有为null才使用锁
        if (singleton == null){
            synchronized (Singleton.class){
                if (singleton == null) singleton = new Singleton();
            }
        }
        return  singleton;
    }
}
    • 通过静态内部类的方式创建
public class Singleton {
    private Singleton(){};

    // 匿名内部类
    private static class SingletonHolder{
        private static final Singleton INSTANCE = new Singleton();
    }

    // 对外报漏一个方法
    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}
    • 通过枚举类实现。饿汉式
public enum Singleton {
   INSTANCE;
}

问题:

使用序列化反序列化、反射回破坏单例模式

解决:

反序列化问题:在类中定义一个readResolve方法,返回创建的实例。

在类中创建一个字段为false,只有第一次访问时正常,并设置字段为true。加锁

2.工厂模式

通过使用一个共同的接口来指向新创建的对象。

  • 简单工厂模式:

客户 -> factory ->不同的对象

只不过是将逻辑放在了工厂里,不用自己new了。但是factory和不同的对象还是产生了新的耦合。

  • 工厂方法模式:

定义一个接口,不同的接口实现类实现不同的方法

客户 -> 接口 -> 实现类 -> 不同的对象

-> 实现类 -> 不同的对象

3.抽象工厂模式

使用的是某一族产品

和工厂模式一样,只不过在接口中多定义了点方法

Collection.iterator方法用的就是抽象工厂模式

工厂接口的实现方法 -> 创建对象(实现了接口的对象)

4.原型模式

用一个已经创建的实例作为原型,通过该原型复制一样的新对象。

结构:

  • 抽象原型类:规定具体原型对象必须实现的clone()方法
  • 具体原型类:实现方法
  • 访问类:使用方法

浅克隆:创建一个新的对象,属性完全一样。对于非基本类型,指向原对象地址。

深克隆:创建一个新的对象,创建新的属性

  • 实现浅拷贝

步骤:

  • 创建一个类实现Cloneable接口
  • 要复制的时候,先创建实例对象,再调用clone方法

如果要实现深克隆:序列化

5.建造者模式

复杂对象的构建与表示分离,同样的构建构造不同的表示。如同装电脑。

定义了一个方法,传入不同的对象,怎么创建是自己定义的,不需要用户管。

和工厂模式一样。

结构:

  • 抽象建造者类(Builder):接口
  • 具体建造者类(ConcreateBuilder):实现接口,定义具体的内容
  • 产品类(Product): 创建的是个啥
  • 指挥者类(Director):传入Builder接口,构造方法确认具体实现。报漏一个接口调用的方法封装

将功能的实现方法定义在一个类中 -> 用户调用的时候传入不同的实现方法。

public class phone {
    private String cpu;
    private String screen;
    private String b;

    // 2.通过构建者Builder对象对外暴露创建
    private phone(Builder builder) {
        this.cpu = builder.cpu;
        this.screen = builder.screen;
        this.b = builder.b;
    }

    public static final class Builder {
        private String cpu;
        private String screen;
        private String b;

        public Builder cpu(String cpu) {
            this.cpu = cpu;
            return this;
        }

        public Builder screen(String screen) {
            this.screen = screen;
            return this;
        }

        public Builder b(String b) {
            this.b = b;
            return this;
        }

        public phone build() {
            return new phone(this);
        }

    }
    
}

总结:

  • 单例模式:只创建一个对象,常用的静态代码块、枚举类
  • 工厂模式:具体功能的实现,接口、实现类、对象的结偶
  • 抽象工厂模式:很多功能放一个接口里
  • 原型模式:复制
  • 建造者模式:注重的组装的过程,具体实现看工厂模式

对于调用接口而不是客户端的工厂/Directer,需要通过用构造方法传入接口的实现方法。客户端在调用工厂的时候传入需要的实现方法。

结构型模式

这些设计模式关注对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。

1.代理模式

概述:

通过代理取获取对象

分为静态代理和动态代理:

  • 静态代理:编译期就生效
  • 动态代理:Java运行期动态生成

结构:

  • 抽象:接口或者抽象类
  • 真实
  • 代理:提供和真实主题相同的接口,含有对真实主题的引用。可以扩展

代理可以进行扩展

Java动态代理

	// 获取真实对象
    private Com com = new Com();

    // 对外提供一个获取代理对象接口的方法
    public Sell getProxy() {
        // 通过Proxy类
        Sell 代理对象 = (Sell) Proxy.newProxyInstance(
                com.getClass().getClassLoader(),
                com.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object invoke = method.invoke(com, args);
                        System.out.println("代理对象");
                        return invoke;
                    }
                });
        return 代理对象;
    }
实现原理:

客户端调用接口的方法,实际调用的是代理类($Proxy0)中的sell方法。

在创建代理类($Proxy0)时,会传入我们输入的method方法,并将此方法传入父类Proxy中,

父类会将传入的方法设置给InvocationHandler接口的invoke方法。

调用代理类($Proxy0)的方法,会调用Proxy父类的InvocationHandler接口invoke的方法,也就是我们自己传入的方法。

invoke方法通过反射执行真实对象所属类的方法。

CGLIB动态代理

没有接口实现动态代理

通过Enhancer实例创建原类的子类对象,继承Method类并设置对象的方法

  • 创建Enhancer对象
  • setSuperClass设置父类 setCallback设置回调函数(继承Method类)
  • create方法货去子类对象

对比:

CGLIB代理和JDK对比

  • CGLIB底层使用ASM生成框架,使用字节码技术获取代理类。不能对final修饰的类或方法进行代理。(本质子类)
  • JDK代理在有接口的情况下使用

动态代理和静态代理

  • 代理对象使用任何方法只需调用一个方法
  • 静态代理代理类也要实现方法,维护高

2.适配器模式

接口转换

InputStreamReader使用

StreamEdcoder继承了InputStream、实现了Reader的接口

InputStreamReader继承了StreamEdcoder类、实现了Reader接口

结构:

  • 目标
  • 适配者
  • 适配器

类适配器模式:继承适配者的功能,实现要适配的接口

对象适配模式:将适配者接口作为自己的参数,实现要适配的接口

3.装饰者模式

BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter

结构:

  • 抽象构建角色:定义一个抽象接口规范准备接收附加责任的对象
  • 具体构建角色:实现抽象构建,通过装饰角色添加职责
  • 抽象装饰角色:继承或实现抽象构建,并包含具体构建的实例,可以通过其子类扩展具体构建的功能
  • 具体装饰角色:实现抽象装饰的相关方法,并给具体构建对象添加附加的责任

我想在你的基础上加点东西,所以我要继承你和包括你,再加点自己的东西。

4.侨接模式

有不同类型的用户 用不同的方法

多对多

给不同的用户自己选择需要什么方法,所以在创建时要传入自己想要的方法

结构:

  1. 抽象化角色:抽象类,包含一个实现化对象的引用
  2. 扩展抽象化角色:抽象化角色的子类,实现父类中的方法,可调用实现化的方法
  3. 实现化角色:定义实现化角色的接口,供扩展抽象角色调用
  4. 具体实现化:给实现化角色实现

5.外观模式

将功能全部隐藏,只对外暴露一个接口

结构:

  1. 外观角色:为多个子系统提供一个共同的接口
  2. 子系统角色:实现系统的部分功能

6.组合模式

树形结构

分类

  • 透明组合模式

所有子模块与抽象接口一样,如果调用未实现的方法,会编译错误

  • 安全组合模式

new 对象的时候自己创建方法

7.享元模式

大量创建相同的对象,但是只用一会,容易资源浪费

结构

  1. 内部状态:不会随着环境的改变而改变的可共享部分
  2. 外部状态:随环境改变而改变的不可以共享的部分
  • 抽象享元角色
  • 具体享元角色
  • 非享元角色
  • 享元工厂

常量池中-128 ~ 127就是提前缓存好的,只需要在用的时候直接调用数组下标即可


行为型模式

对象的组合 -> 完成任务

责任链模式(Chain of Responsibility Pattern)

if else

结构:

  • 抽象处理者:定义一个处理请求的接口,下一后继连接
  • 具体处理者:实现请求,不行就传给后继连接
  • 客户类:传入个数值

命令模式(Command Pattern)

类似于消息队列,发消息 与 接收消息 的对象进行解耦

Runnable接口相当于命令角色,Thread相当于调用者,start方法相当于方法

Thread包含并下达Runnable命令 Runnable下的实现方法包含了实现对象和实现方法

结构

  • 抽象命令类
  • 具体命令类
  • 接收者
  • 调用者

解释器模式(Interpreter Pattern)

根绝定义的规定,解析这个语句

迭代器模式(Iterator Pattern)

一个对象属性访问聚合对象的数据,而不暴露内部对象。

把迭代的方法放在迭代器里实现,在集合中只要选择迭代器的一个实现类,让这个实现类去完成迭代就行了

结构:

  • 抽象聚合角色:
  • 具体聚合对象
  • 抽象迭代器角色
  • 具体迭代器角色

中介者模式(Mediator Pattern)

将所有对象都介入中介者,所有类的关系通过中介者

结构:

  • 抽象中介者
  • 具体中介者
  • 抽象同事类
  • 具体同事类

备忘录模式(Memento Patter)

回滚

结构:

  • 发起人
  • 备忘录
  • 管理者

观察者模式(Observer Pattern)

一对多的状态,多个监听器监听某一个主题对象。

发布——订阅 模式

结构:

  • 抽象主题(抽象被观察者),抽象主题角色把所有观察者保存在一个集合中,对外提供增加和删除观察者对象
  • 具体主题(具体被观察者)
  • 抽象观察者
  • 具体观察者
    • 窄接口
    • 宽接口

状态模式(State Pattern)

不同的逻辑状态有不同的方法

结构:

  • 环境角色
  • 抽象状态角色
  • 具体状态橘色

空对象模式(Null Object Pattern)

策略模式(Strategy Pattern)

一个要求有很多个方法可以实现,选哪个交给用户决定

将算法实现和算法调用进行解耦

结构:

  • 抽象策略类
  • 具体策略:提供具体的抽象策略的实现
  • 环境:只有一个策略类的引用,最终给客户端引用

模板模式(Template Pattern)

结构:

  1. 抽象类
    1. 模版方法:骨架
    2. 基本方法:具体实现骨架
      1. 抽象方法
      2. 具体方法
      3. 钩子方法
  1. 具体子类

InputStream

访问者模式(Visitor Pattern)

封装一些作用于某种数据结构的各元素的操作,在不改变数据结构的前提下定义操作

操作

  • 抽象访问者
  • 具体访问者
  • 抽象元素角色
  • 具体元素角色
  • 结构对象角色