黑马-设计模式-笔记(未完)

本文详细介绍了UML类图、软件设计原则以及各种设计模式,如单例、工厂、原型、建造者等创建型模式,以及代理、适配器、装饰者等结构型模式,展示了如何通过这些模式组织和复用代码,提高软件设计灵活性和可维护性。
摘要由CSDN通过智能技术生成

一、基础

UML类图

可见性:

  • + public
  • - private
  • #protected
    表示方式:
  • 属性:可见性 名称:类型[=默认值]
  • 方法:可见性 名称(参数)[:返回类型]
    关系:
  • 关联关系:实线,引用关系,类属性里有另一个类
  • 聚合关系:空心菱形,表示整体和部分,类属性是另一个类的集合
  • 组合关系:实心菱形,强烈聚合关系,类属性是另一个类,控制它的存在
  • 依赖关系:虚线,类方法参数里有另一个类,(耦合度最低)
  • 继承关系:空心实线三角,泛化关系,表示一般与特殊,(耦合度最高)
  • 实现关系:空心虚线三角,接口和实现类关系
软件设计原则

单一职责原则:一个类只负责一个职责
里氏代换原则:子类可以直接替换父类,可以扩展父类的方法,但不能改变父类原有功能
开闭原则:对扩展开放,对修改关闭,实现热插拔
依赖倒转原则:模块间要依赖抽象,不要依赖实现,客户和实现解耦
接口隔离原则:接口最小粒度设计,一个类对另一个类尽量少依赖不相关的方法,抽象接口细拆开进行实现
迪米特法则:两个模块无需直接通讯就无需直接调用,使用第三方转发降低耦合度
合成复用原则:尽量先使用关联关系实现,其次才是继承复用,父类对子类是透明的(白箱复用)

一、创建型模式

如何创建对象,将对象的创建和使用分离

1.单例模式
结构
  • 单例类:只能创建一个实例的类
  • 访问类:使用单例类
分类
  • 饿汉式:类加载就会导致该单例对象被创建
    静态变量方式
public class Singleton {  
  
    // 1.私有构造方法  
    private Singleton() {}  
  
    // 2.在本类中创建该类对象  
    private static Singleton instance = new Singleton();  
  
    // 3.提供公共访问方式  
    public static Singleton getInstance() {  
        return instance;  
    }  
}

静态代码块方式

public class Singleton {  
  
    // 1.私有构造方法  
    private Singleton() {}  
  
    // 2.声明Singleton类型变量  
    private static Singleton instance; // null  
  
    // 3.静态代码块赋值  
    static {  
        instance = new Singleton();  
    }  
  
    // 4.提供公共访问方式  
    public static Singleton getInstance() {  
        return instance;  
    }  
}

枚举方式
枚举类线程安全只会装载一次,唯一不会被破坏的单例模式

public enum Singleton {  
    INSTANCE;  
}
  • 懒汉式:首次使用对象时才被创建
    方式一:判断并加锁
public class Singleton {  
  
    // 1.私有构造方法  
    private Singleton() {}  
  
    // 2.声明Singleton类型变量  
    private static Singleton instance;  
  
    // 3.提供公共访问方式  
    public static synchronized Singleton getInstance() {  
        // 判断instance是否为null  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

方式二:双重检查锁 写操作才加锁优化性能

public class Singleton {  
  
    // 私有构造方法  
    private Singleton() {}  
  
    // 声明对象 需要volatile保证有序性
    private static volatile Singleton instance;
  
    // 对外提供方法  
    public static Singleton getInstance() {  
        // 第一次判断  
        if (instance == null) {  
            synchronized (Singleton.class){  
                // 第二次判断  
                if (instance == null) {  
                    instance = new Singleton();  
                }  
            }  
        }  
  
        return instance;  
    }  
}

方式三:静态内部类
JVM加载时不会加载内部类,只有调用内部类时才会加载

public class Singleton {  
  
    // 私有构造方法  
    private Singleton() {}  
  
    // 定义一个静态内部类  
    // JVM加载时不会加载内部类,只有调用内部类时才会加载  
    private static class SingletonHolder{  
        // 在内部类中声明并初始化外部类的对象  
        private static final Singleton INSTANCE = new Singleton();  
    }  
  
    // 对外提供方法  
    public static Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
    }  
}
问题
  • 破坏单例模式
    • 序列化、反序列化:通过ObjectOutStream和ObjectInputStream对对象进行反序列化生产新的对象
      • 解决方法:在单例类中增加readResolve()方法返回单例对象
    • 反射:通过反射获取无参构造函数并放权
      • 解决方法:在单例类无参构造方法中增加判断并返回单例对象
2.工厂模式
简单工厂模式/静态工厂模式

把对象创建和业务分开,有新产品只需要修改工厂类;但是产品和工厂还有耦合,新产品还需要改工厂违反开闭

组成
  • 具体工厂:提供了创建产品的规范,调用者通过该方法创建产品
  • 抽象产品:定义产品规范
  • 具体产品:实现或继承抽象产品的子类
    ![[20240424_设计模式 GoF_1.png]]
工厂方法模式

用户只需知道具体工厂名称;新增产品只需添加具体产品和具体工厂类,无需对原工厂修改;但是增加了系统复杂

组成
  • 抽象工厂:提供创建产品的接口,调用者通过它访问具体工厂来创建产品
  • 具体工厂:提供了创建产品的规范,调用者通过该方法创建产品
  • 抽象产品:定义产品规范
  • 具体产品:实现或继承抽象产品的子类
    在这里插入图片描述
抽象工厂模式

可以保证用户使用同一个产品族的产品;但是产品族加一个产品,所有工厂类都需要修改

组成
  • 抽象工厂:提供创建产品的接口,包含多个创建产品的方法,创建多个不同等级的产品
  • 具体工厂:提供了创建产品的规范,调用者通过该方法创建产品
  • 抽象产品:定义产品规范
  • 具体产品:实现或继承抽象产品的子类
    ![[20240424_设计模式 GoF_2.png]]
3.原型模式

用一个已创建的实例为原型创建新对象,适用于对象创建复杂,对性能安全有要求

浅克隆:非基本类型指向原有内存地址
深克隆:完全一致并独立的拷贝,可以使用序列化或者递归浅克隆或其他方式实现

组成
  • 抽象原型类:规定了具体原型对象必须实现的clone方法,通常是Cloneable接口
  • 具体原型类:实现抽象原型类的clone方法
  • 访问类:使用具体原型类的clone方法来复制新对象
4.建造者模式

将复杂对象的构建和表示分离,使同样的构建可以创建不同的表示
适用于构建复杂且各个部分独立,构建流程相对一致的
可以通过内部建造类实现链式编程

组成
  • 抽象建造者类:接口规定都有哪些部分要创建
  • 具体建造者类:实现抽象建造者,提供具体构建各个部分的方法,完成后提供产品实例
  • 产品类:要创建的复杂对象
  • 指挥者类:调用具体建造者创建各个部分,只负责按顺序或完整创建
    在这里插入图片描述

二、结构型模式

如何将类或对象按布局组成更大的结构

1.代理模式

访问对象不直接引用目标对象;有静态代理(编译时生成)和动态代理(java运行时动态生成 JDK代理、CGLib代理)

组成
  • 抽象主题类:通过接口或抽象类声明真实主题和代理对象的业务方法
  • 真实主题类:实现具体业务,是代理对象代表的真实对象,是最终要引用的对象
  • 代理类:提供了与真实主题相同的接口,内部是对真实主题引用
静态代理

直接在代理类中增加真实主题类的成员变量,在方法中调用真实主题类的成员变量
在这里插入图片描述

JDK动态代理
JDK动态代理

java中提供动态代理类Proxy,里面有静态方法newProxyInstance获取代理对象

  1. 在测试类中通过代理对象调用sell()方法
  2. 根据多态特性,执行的是代理类($Proxt0)中的sell方法
  3. 代理类($Proxy0)中的sell方法中调用类InvocationHandler接口的子实现的invoke方法
  4. invoke方法通过反射执行类真实对象所属类(TrainStation)的sell方法
public class ProxyFactory {  
  
    // 声明目标对象  
    private TrainStation station = new TrainStation();  
  
    public SellTickets getProxyInstance() {  
        // 返回代理对象  
        /**  
         * ClassLoader loader 类加载器,用于加载代理类,可以通过目标对象获取类加载器  
         * Class<\?> interfaces 代理类实现接口的字节码文件  
         * InvocationHandler h 代理对象的调用处理程序  
         * */  
        return (SellTickets) Proxy.newProxyInstance(  
                station.getClass().getClassLoader(),  
                station.getClass().getInterfaces(),  
                new InvocationHandler() {  
                    /**  
                     * proxy 代理对象,在invoke方法中基本不用  
                     * method 目标对象的方法  
                     * args 方法的参数  
                     * */  
                    @Override  
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
                        // 增强  
                        System.out.println("代理点收取一些服务费用(JDK代理)");  
  
                        // 代理原方法  
                        return method.invoke(station, args);  
                    }  
                }  
        );  
    }  
}
CGLib动态代理

cglib代理的是子类
实现MethodInterceptor并重写intercept方法,所以不能使用在声明为final的

public class ProxyFactory implements MethodInterceptor {  
  
    private TrainStation trainStation = new TrainStation();  
    public TrainStation getProxyInstance(){  
        // 创建enhance对象,类似JDK代理中的Proxy类  
        Enhancer enhancer = new Enhancer();  
        // 设置父类的字节码文件  
        enhancer.setSuperclass(TrainStation.class);  
        // 设置回调函数  
        enhancer.setCallback(this);  
        // 创建代理对象  
        return (TrainStation) enhancer.create();  
    }  
  
    @Override  
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {  
        System.out.println("cglib代理模式");  
        method.invoke(trainStation,objects);  
        return null;  
    }  
}

有接口就使用JDK动态代理,没有就用CGLib动态代理;最好不使用静态代理,因为维护成本高

2.适配器模式

将一个类的接口转换为期待的接口

组成
  • 目标接口(Target):当前业务期待的接口,可以是抽象类或接口
  • 适配者类(Adaptee):是被访问和适配的现存组件库中的组件接口
  • 适配器类(Adapter):是转换器,通过继承或引用适配者的对象,把适配者的接口转换
    ![[20240425_设计模式 GoF.png]]
类适配器

定义适配器实现目标接口,并继承适配器类
耦合度高,违反合成复用原则,有目标接口才能用

public class SDAdapterTF extends TFCardImpl implements SDCard {  
    @Override  
    public String readSD() {  
        System.out.println("adapter read tf card");  
        return readTF();  
    }  
  
    @Override  
    public void writeSD(String msg) {  
        System.out.println("adapter write tf card");  
        writeTF(msg);  
    }  
}
对象适配器

要求程序员了解现有组件库的内部,使用较少

public class SDAdapterTF implements SDCard {  
  
    // 声明适配者类  
    private final TFCard tfCard;  
  
    public SDAdapterTF(TFCard tfCard) {  
        this.tfCard = tfCard;  
    }  
  
    @Override  
    public String readSD() {  
        System.out.println("adapter read tf card");  
        return tfCard.readTF();  
    }  
  
    @Override  
    public void writeSD(String msg) {  
        System.out.println("adapter write tf card");  
        tfCard.writeTF(msg);  
    }  
}
3.装饰者模式

不改变现有对象结构基础上,动态给改对象增加附加功能
继承是静态的,装饰是动态的,遵循开闭原则

组成
  • 抽象构件角色(Component):定义抽象接口,规范接受附加功能对象
  • 具体构件角色(Concrete Component):实现抽象构件,通过装饰角色为其增加功能
  • 抽象装饰角色(Decorator):继承或实现抽象构件,并包含具体构件实例,通过子类扩展具体构件功能
  • 具体装饰角色(Concrete Decorator):实现抽象装饰,为具体构件增加功能
    ![[20240426_0 设计模式 GoF.png]]
与静态代理的区别
  • 相同点
    • 都要实现与目标类相同的业务接口
    • 在两个类中都要声明目标对象
    • 都可以在不修改目标类的前提下增强目标类
  • 不同点
    • 目的不同,装饰者为了增强目标对象;静态代理为了保护隐藏对象
    • 获取目标对象构建的地方不同,装饰者是外部传递;静态代理是代理类内部创建
4.桥接模式

将抽象与实现分离,帮助一批对象用组合关系代替继承关系

结构
  • 抽象化角色(Abstraction):定义抽象类,并包含一个对实现化对象的引用
  • 扩展抽象化角色(Refined Abstraction):抽象化角色的子类,实现父类业务员方法,并通过组合关系调用实现化角色业务方法
  • 实现化角色(Implementor):定义实现化角色接口,供扩展抽象化角色调用
  • 具体化角色(Concrete Implementor):给出实现化角色接口的具体实现
    在这里插入图片描述
5.外观模式

又名门面模式,迪米特法则的应用,对外提供统一接口
解耦子系统和客户端,但是不符合开闭原则

组成
  • 外观角色(Facade):为多个子系统对外提供公共接口
  • 子系统角色(Sub System):实现系统的部分功能,客户通过外观角色访问
    ![[20240427_0 设计模式 GoF_1.png]]
6.组合模式

又名部分整体模式,把一组相似对象当作单一对象(树形结构)

组成
  • 抽象根节点(Component):定义系统各层次对象的共有方法和属性
  • 树枝节点(Composite):存储子节点,组合树枝节点和叶子结点形成一个树形结构
  • 叶子结点(Leaf):叶子结点对象,其下再无分枝,是系统层次遍历的最小单位
    ![[20240428_0 设计模式 GoF.png]]
7.享元模式

运用共享技术支持大量细粒度对象的复用,减少创建对象的数量,提高系统资源利用率
分离内部状态和外部状态会使程序逻辑复杂
系统有大量相同或相似对象,大部分状态可以外部化,需哟啊维护一个存储享元对象的享元池

状态

区分应用中的两种状态,并将外部状态外部化

  • 内部状态:不会随着环境的改变而改变的可共享部分
  • 外部状态:随环境改变的不可共享部分
组成
  • 抽象享元角色(Flyweight):一个接口或抽象类,声明享元类公共方法,向外界提供享元对象的内部数据(内部状态),也可以设置外部数据(外部状态)
  • 具体享元角色(Concrete Flyweight):实现抽象享元类,享元对象;在具体享元类中为内部状态提供存储空间。通常结合单例模式来设计具体享元类,为每个具体享元类提供唯一享元对象
  • 非享元角色(Unsharable Flyweight):不被共享的子类,当需要一个非共享具体享元类对象时可以直接实例化创建
  • 享元工厂(Flyweight Factory):负责创建和管理享元类角色;当请求享元对象时检查系统是否存在符合要求的享元对象,若存在提供,否则创建
    ![[20240510_0 设计模式 GoF.png]]

如何让类或对象协作完成任务
分为类行为型模式和对象行为型模式

1.模板方法模式

定义操作中的算法骨架,将算法一些步骤延迟到子类中
适合步骤固定,将容易变化的部分抽象供子类实现;通过子类决定父类的某个步骤是否执行,反向控制

组成
  • 抽象类:负责给出算法骨架,由一个模板方法和若干基本方法构成
    • 模板方法:定义算法骨架,按顺序调用基本方法
    • 基本方法
      • 抽象方法:由抽象类声明,其子类实现
      • 具体方法:由抽象类或具体类声明并实现,其子类可以覆盖或继承
      • 钩子方法:抽象类中实现,包括用于判断的逻辑方法、需要子类重写的空方法。一般用于判断的逻辑方法,isXXX,返回boolean
  • 具体子类:实现抽象类中所定义的方法和钩子方法
    在这里插入图片描述
2.策略模式

对算法进行封装,委派给不同对象对算法进行管理
减少使用if-else,但是客户端需要知道所有策略类

组成
  • 抽象策略(Strategy):一个接口或抽象类,给出所有具体策略所需的接口
  • 具体策略(Concret Strategy):实现抽象策略,提供具体算法实现或行为
  • 环境类(Context):持有一个策略类的引用,最终给客户端调用
    ![[20240519_0 设计模式 GoF_1.png]]
3.命令模式

将请求封装为一个对象,请求的发起和执行通过命令对象沟通

组成

抽象命令类(Command):定义命令接口,声明执行方法
具体命令类(Concrete Command):实现命令接口,通常会持有接收者的功能来完成
实现者/接受者(Receiver):真正命令执行者,任何类都可能是接受者,只要能实现命令要求的功能
调用者/请求者(Invoker):要求命令对象执行请求,可以持有很多命令对象,命令对象的入口
![[20240522_0 设计模式 GoF.png]]

4.职责链模式
5.状态模式
6.观察者模式
7.中介者模式
8.迭代器模式
9.访问者模式
10.备忘录模式
11.解释器模式
  • 15
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值