Java实现七种结构型模式

(一) 桥接模式

桥接模式(Bridge Pattern): 又称之为接口模式, 将 抽象部分 与 实现部分 分离, 使它们都可以独立地变化. 属于对象结构模型的一种

桥接模式基于类的最小设计原则, 通过使用封装、聚合及继承等行为让不同的类承担不同的职责. 它最主要特点是把 抽象 与 行为实现 分离开来, 从而可以保持各部分的独立性以及应对他们的功能扩展

举例: 抽象类Shape中存在draw绘画的抽象方法, 可以画 圆形、正方形、长方形等, 又还需要给这些形状进行上色, 如白色、红色、黑色等.

第一种设计方案: 我们可以设计为每一个形状提供每一种颜色的类, UML类图表示为:

在这里插入图片描述
此设计方案存在的问题:

  • 扩展性问题(类爆炸): 如果要新添加一个菱形, 就需要创建一个菱形类和二个具体颜色菱形类(白色和红色). 又如果, 此时要添加一种新的颜色: 黑色, 那么需要创建两个黑色的图形类(圆形和正方形)
  • 违反了单一职责原则: 新增一种形状时, 却要新增各个颜色的具体形状

第二种设计方案: 影响创建最终图形有两个因素(维度), 形状(主维度) 和 颜色(次维度), 我们希望可以根据实际需求对形状和颜色进行组合. 对于多个变化维度, 可以采用桥接模式, 将 抽象部分 与 实现部分 分离.

第一种方案中的 抽象部分(Share) 与 实现部分(WhiteCircle、WhiteSquare…) 是继承关系(没有分离), 要将 继承关系 改为 聚合关系(分离). 博主理解的是将 两个维度: 形状 和 颜色, 由原来的继承关系 变成 聚合关系

在这里插入图片描述
次维度接口(颜色)

interface Color {
    void bepaint(String shape); // 为 shape形状 着色
}

次维度接口实现类

class RedColor implements Color {

    @Override
    public void bepaint(String shape) {
        System.out.println("红色的" + shape); 
    }
}

class WhiteColor implements Color {

    @Override
    public void bepaint(String shape) {
        System.out.println("白色的" + shape);
    }
}

主维度抽象类(桥), 拥有次维度接口成员属性. 主维度 和 次维度 组合关系

abstract class Shape {
    private Color color;

    public Shape(Color color) {
        this.color = color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    abstract void draw();
}

主维度实现类, 通过主维度抽象类(桥) 调用 次维度接口方法

class Circle extends Shape {

    public Circle(Color color) {
        super(color);
    }

    @Override
    void draw() {
        color.bepaint("圆形");
    }
}

class Square extends Shape {

    public Square(Color color) {
        super(color);
    }

    @Override
    void draw() {
        color.bepaint("正方形");
    }
}

测试:

public class BridgePattern {
    public static void main(String[] args) {
        Circle whiteCircle = new Circle(new WhiteColor());
        whiteCircle.draw();
        Circle redCircle = new Circle(new RedColor());
        redCircle.draw();

        Square whiteSquare = new Square(new WhiteColor());
        whiteSquare.draw();
        Square redSquare = new Square(new RedColor());
        redSquare.draw();
    }

}

在这里插入图片描述
桥接模式的注意事项和细节

  • 实现了抽象和实现部分的分离, 从而极大的提功力系统的灵活性, 让抽象部分和实现部分独立分开来, 这有助于系统进行分册设计, 从而生产更好的结构化系统
  • 桥接模式替代多重继承方案, 可以减少子类的个数, 降低系统的管理和维护成本
  • 桥接模式的引入增加了系统理解和设计难度, 由于聚合关联关系建立在抽象层, 要求开发者针对抽象进行设计和编程
  • 桥接模式要求正确识别出系统中两个或逗哥独立变化的维度, 适用于 不希望使用继承多层继承导致系统类的个数急剧增加的系统.


(二) 装饰者模式

装饰者模式(Decorator Pattern): 在不改变原有对象的基础之上, 动态的将新功能附加到对象上, 在对象功能扩展方面, 它比继承更有弹性, 装饰者模式也提现了开闭原则(OCP)

举例: 有一家咖啡店, 已出售的咖啡种类有: 摩卡和拿铁咖啡. 现在需要在已有的咖啡种类上添加调味: 牛奶 和 茶. 可自由组合, 如: 一份摩卡咖啡加一份牛奶、一份拿铁咖啡加两份茶… UML类图所示:

在这里插入图片描述

咖啡抽象类和具体咖啡实体: 咖啡抽象类是 具体咖啡 和 抽象装饰类 的共同父类

abstract class Coffee {
    public abstract String getDes(); // 描述
    public abstract Float getPrice(); // 价格
}

class MochaCoffee extends Coffee {
    @Override
    public String getDes() {
        return "摩卡咖啡";
    }

    @Override
    public Float getPrice() {
        return 10.5f;
    }
}

class LatteCoffer extends Coffee {
    @Override
    public String getDes() {
        return "拿铁咖啡";
    }

    @Override
    public Float getPrice() {
        return 20.5f;
    }
}

抽象装饰器类: 继承抽象类, 组合抽象类. 用于给具体实体类增加职责

class AbstractDecorator extends Coffee {
    protected Coffee coffee;

    public AbstractDecorator(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public String getDes() {
        return coffee.getDes();
    }

    @Override
    public Float getPrice() {
        return coffee.getPrice();
    }
}

牛奶装饰器: 继承抽象装饰器, 在抽象父类加入牛奶, 且价格加 2 元
茶装饰器: 继承抽象装饰器, 在抽象父类加入茶, 且价格加 2.5 元

class MikeDecorator extends AbstractDecorator {

    public MikeDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDes() {
        return coffee.getDes() + " 加入一份牛奶";
    }

    @Override
    public Float getPrice() {
        return coffee.getPrice() + 2F;
    }
}

class TeaDecorator extends AbstractDecorator {

    public TeaDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDes() {
        return coffee.getDes() + " 加入一份茶";
    }

    @Override
    public Float getPrice() {
        return coffee.getPrice() + 2.5F;
    }
}

测试:

public class DecoratorPattern {

    public static void main(String[] args) {
        // 单点一份 摩卡咖啡
        Coffee coffee = new MochaCoffee();
        System.out.println(coffee.getDes() + ", 价格: " + coffee.getPrice());

        // 摩卡咖啡 + 一份牛奶
        coffee = new MikeDecorator(coffee);
        System.out.println(coffee.getDes() + ", 价格: " + coffee.getPrice());

        // 摩卡咖啡 + 两份牛奶
        coffee = new MikeDecorator(coffee);
        System.out.println(coffee.getDes() + ", 价格: " + coffee.getPrice());

        // 摩卡咖啡 + 两份牛奶 + 一份茶
        coffee = new TeaDecorator(coffee);
        System.out.println(coffee.getDes() + ", 价格: " + coffee.getPrice());

    }
}

在这里插入图片描述



(三) 组合模式

组合模式(Composite Pattern): 又称之为部分整体模式, 是用于把一组相似的对象当作一个单一的对象. 组合模式依据树形结构来组合对象, 用来表示 “整体-部分” 的层次关系.

组合模式使得用户对单个对象 和 组合对象的访问具有一致性, 即: 能让客户以一致的方式处理单一对象 和 组合对象

举例: 学校院系展示需求, 展示出: 一个学校有多少个学院, 每个学院有多少个系.
在这里插入图片描述

采用组合模式分析:

  1. 抽取 一组相似的对象(学校、学院、系) 中共有的属性和方法 组成一个单一的对象(Component)
    - 属性: 名称, 描述, 创建时间 …
    - 方法: 打印对象信息的方法, 添加、删除、修改的方法…
  2. 以依据树形结构来组合对象, 用来表示 “整体-部分” 的层次关系
    在这里插入图片描述
  3. UML类图展示: 用集合表示是否有下一层
    在这里插入图片描述

组合模式中的角色:

  • Component角色: 将 一组相似的对象 抽取 一个单一的共同对象Component(树结构中的子节点), 共同对象中拥有 这组相似的对象 共有的属性和方法
  • Composite角色: 非叶子节点, 继承Component公共类, 覆盖重写所有的公共方法
  • Leaf角色: 叶子节点, 继承Component公共类, 没有下一层(集合), 无需实现所有的公共方法

Component公共类: 抽取了 名称公共属性 和 添加、删除、打印信息的公共方法

abstract class Component {

    protected String name; // 名称

    public Component(String name) {
        this.name = name;
    }
	
	// 打印Component共同对象信息
    public abstract void printInfo(); 

    // 默认实现 一组相似对象 中共有的接口: 添加add、删除remove
    public void add(Component component) {
        throw new UnsupportedOperationException();
    }

    public void remove(Component component) {
        throw new UnsupportedOperationException();
    }
}

大学实体类Composite: 拥有学院层(学院集合)

class University extends Component {

    // 学院列表
    private List<Component> colleges = new ArrayList<>();

    public University(String name) {
        super(name);
    }

    @Override
    public void printInfo() {
        System.out.println("----------------" + super.getName() + "----------------");
        for (Component college : colleges) {
            college.printInfo(); // 打印学院信息
        }
    }

    @Override
    public void add(Component component) {
        colleges.add(component);
    }

    @Override
    public void remove(Component component) {
        colleges.remove(component);
    }
}

学院实体类Composite: 拥有系列层(系列集合)

class College extends Component {

    private List<Component> departments = new ArrayList<>();

    public College(String name) {
        super(name);
    }

    @Override
    public void printInfo() {
        System.out.println("----------------" + super.getName() + "----------------");
        for (Component department : departments) {
            department.printInfo(); // 打印学院信息
        }
    }

    @Override
    public void add(Component component) {
        departments.add(component);
    }

    @Override
    public void remove(Component component) {
        departments.remove(component);
    }
}

系实体类Leaf: 没有下一层, 叶子节点, 不需要实现某些共有的方法 add remove

class Department extends Component {

    public Department(String name) {
        super(name);
    }

    @Override
    public void printInfo() {
        System.out.println(super.getName());
    }
}

测试:

public class CompositePattern {
    public static void main(String[] args) {
        University university = new University("清华大学");
        // 添加学院
        College computeCollege = new College("计算机学院");
        College infoCollege = new College("信息工程学院");
        university.add(computeCollege);
        university.add(infoCollege);
        // 添加系
        computeCollege.add(new Department("软件工程"));
        computeCollege.add(new Department("网络工程"));
        infoCollege.add(new Department("通信工程"));
        infoCollege.add(new Department("信息工程"));
        university.printInfo();
    }
}

在这里插入图片描述

组合模式的总结

  • 简化客户端操作. 客户端只需要面对一致的对象Component而不用考虑整体部分或者结点叶子
  • 具有较强的扩展性. 当需要更改组合对象时, 只需要调整内部的层次关系,


(四) 外观模式

外观模式(Facade Pattern): 又称之为过程模式, 外观模式为子系统类中的一组接口提供一个一致的界面, 此模式定义了一个高层接口, 用以屏蔽内部子系统的细节, 使得调用(客户)端只需要跟这个接口发送调用, 而无需关心这个子系统的内部细节

外观模式中的角色:

  • Facade外观角色: 组合子系统类, 外观类对客户端提供统一的调用接口. 外观类知道 各个子系统类中的接口的具体功能, 从而将客户端的请求 代理给适当的 子系统对象
  • Subsystem子系统角色: 是具体功能的实际提供者, 处理Facade 对象指派的任务.

举例: 银行ATM机器采用的是外观模式, 向用户提供业务功能(存取款), 用户只需要选择对应的功能, 就能完成对应的业务(存取款), 用户无需知道存取款业务的具体流程

  • ATM外观角色: 提供存款、取款业务(接口)
  • 银行卡子系统: 记录 账户、密码、余额 的具体功能
  • 银行子系统: 校验用户、输入操作金额、校验金额、具体业务操作功能

在这里插入图片描述

银行卡子系统: 提供 账户、密码具体功能

class BankCard {

    private static BankCard bankCard = new BankCard();

    public static BankCard getBankCard() {
        return bankCard;
    }

    public void inputAccount() {
        System.out.println("输入账号");
    }

    public void inputPwd() {
        System.out.println("输入密码");
    }
}

银行子系统: 提供 输入操作金额、校验金额、存钱、取钱的具体功能

class Bank {
    private static Bank bank = new Bank();

    public static Bank getBank() {
        return bank;
    }

    public void operationMoney() {
        System.out.println("输入操作金额");
    }

    public void verifyMoney() {
        System.out.println("校验金额数量、真假");
    }

    public void saveMoney() {
        System.out.println("存款成功");
    }

    public void withdrawalMoney() {
        System.out.println("提款成功");
    }
}

ATM外观: 提供存款、取款业务接口

class ATMFacade {

    private BankCard bankCard = BankCard.getBankCard();
    private  Bank bank = Bank.getBank();

    /**
     * 存款业务
     */
    public void saveBusiness() {
        bankCard.inputAccount();
        bankCard.inputPwd();
        bank.operationMoney();
        bank.verifyMoney();
        bank.saveMoney();
    }

    /**
     * 取款业务
     */
    public void withdrawalBusiness() {
        bankCard.inputAccount();
        bankCard.inputPwd();
        bank.operationMoney();
        bank.verifyMoney();
        bank.withdrawalMoney();
    }
}

测试

public class FacadePattern {
    public static void main(String[] args) {
        ATMFacade bankFacade = new ATMFacade();
        System.out.println("---------存款业务---------");
        bankFacade.saveBusiness();
        System.out.println("---------取款业务---------");
        bankFacade.withdrawalBusiness();
    }
}

在这里插入图片描述
外观模式的总结

  • 外观模式对外屏蔽了子系统的细节, 因此外观模式降低了客户端对子系统使用的复杂性
  • 外观模式对 客户端与子系统进行了解耦, 让子系统内部的模块更易维护和扩展
  • 通过合理的的使用外观模式, 可以帮我们更好的划分访问层次(MVC)


(五) 享元模式

享元模式(Flyweight Pattern): 又称之为蝇量模式, 运用共享技术有效地支持大量细粒度的对象. 常与工厂模式一同使用. 享元模式经典的应用场景就是池技术: String常量池、数据库连接池、缓冲池等等(使用对象时 , 先从对象池中获取对象 , 如果对象池中没有 , 创建一个 , 放入对象池 , 然后再从对象池中获取)

享元模式能够解决 创建重复对象的内存浪费的问题, 当系统中有大量相似对象, 可以提供缓冲池, 不需要总是创建新的对象, 可以从缓冲池中取出, 从而达到降低系统内存,同时提高效率的目的

细粒度对象: 对象数量多且对象属性(性质)相似, 将细粒度对象中的属性分成两部分

  • 内部状态: 指对象共享出来的的信息, 存储在享元对象内部且不会随环境的改变而改变(围棋棋子的颜色:白色 和 黑色)
  • 外部状态: 指对象得以依赖的一个标记, 是随环境的变化而改变的, 不可共享的状态(棋子的位置)

享元模式中的角色:

  • Flyweight 抽象享元类: 通常是一个接口或者抽象类, 是细粒度对象的抽象类
  • ConcreteFlyweight 具体享元类: 实现了Flyweight, 是具体的细粒度对象, 在抽象享元类和具体的享元类中定义内部状态和外部状态
  • FlyweightFactory 享元工厂类: 用于构建一个池容器(Map集合), 从这个池容器中获取具体的享元类, 从而达到共享对象的目的


举例: 有一篇文章笔记, 写的非常有技术含量. 此时恰巧有三位童鞋(小明、小红、小刚)想转载这篇笔记, 但他们的转载形式不一样

  • 小明和小刚想以博客的形式转载这篇文章
  • 而小红想以网站的形式转载这篇文章

可以采用享元模式来思考解决问题

  • 确定细粒度对象(对象数量多且对象属性(性质)相似): 笔记转载对象, 由笔记 + 转载形式 + 转载者 构成
  • 分析内部状态(不会随环境的改变而改变): 笔记的内容、转载形式(博客、网站), 这些内部状态时可共享的
  • 分析外部状态(随环境的变化而改变): 转载者(无法确定转载者的数量), 无法共享的状态
    在这里插入图片描述

抽象享元类: 提供一个抽象的转载文章的方法: reprint(String 转载者), 定义了外部状态

abstract class NoteFlyweight {

    /**
     * 笔记转载
     *  author:   笔记的外部状态, 转载者(随转载者的不同而不同, 不可共享的状态)
     */
    abstract void reprint(String publisher);
}

具体享元角色, 继承抽象享元类, 定义了 转载形式 内部状态

class ConcreteNote extends NoteFlyweight {

    // 笔记的内部状态, 转载形式(博客、网站, 可共享的状态) 定义在抽象享元类的实现类中
    private String type;

    public ConcreteNote (String type) {
        this.type = type;
    }

    @Override
    void reprint(String publisher) {
        System.out.println("笔记转载者: " + publisher + "; 笔记的转载类型: " + type);
    }
}

享元工厂类: 用于构建一个池容器(Map集合), 从这个池容器中根据 转载形式(内部状态) 获取具体的享元类

class FlyweightFactory {
    private Map<String, ConcreteNote> pool = new HashMap<>();

	// 根据 转载形式(内部状态) 获取具体的享元类
    public NoteFlyweight getNodeByType(String type) {
        if (!pool.containsKey(type)) {
            pool.put(type, new ConcreteNote(type));
        }
        return pool.get(type);
    }

	// 池容器 存储 享元类的个数
    public int getNodeCount() {
        return pool.size();
    }
}

测试:

public class FlyweightPattern {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();

        // 小明以博客的形式转载此笔记
        NoteFlyweight node1 = factory.getNodeByType("博客"); // 从工厂池中取出可共享的笔记对象
        node1.reprint("小明"); // 可共享的笔记对象 + 不可共享的转载者

        // 小红以博客的形式转载此笔记
        NoteFlyweight node2 = factory.getNodeByType("网站"); // 从工厂池中取出可共享的笔记对象
        node2.reprint("小红"); // 可共享的笔记对象 + 不可共享的转载者

        // 小刚以博客的形式转载此笔记
        NoteFlyweight node3 = factory.getNodeByType("博客"); // 从工厂池中取出可共享的笔记对象
        node3.reprint("小刚"); // 可共享的笔记对象 + 不可共享的转载者

        System.out.println();
        System.out.println("池容器 存储 享元类的个数 = " + factory.getNodeCount());
    }
}

在这里插入图片描述



(六) 代理模式

代理模式(ProxyPattern): 为一个对象提供一个替身, 以控制对这个对象的访问. 即通过代理对象访问目标对象. 可以在目标对象实现的基础上, 增强额外的功能操作, 即扩展目标对象的功能

代理模式有三种形式:

  • 静态代理
  • 动态代理(动态代理、接口代理)
  • Cglib代理: 可以在内存动态的创建对象, 而不需要实现接口

静态代理: 需要定义接口或者父类, 被代理对象(目标对象) 与 代理对象 需要一同实现相同的接口或者是继承相同的父类
在这里插入图片描述

// 教师接口
interface ITeacher {
    void teach();
}

// 教师实现类, 被代理对象
class Teacher implements ITeacher {
    @Override
    public void teach() {
        System.out.println("教师正在授课...");
    }
}

// 代理对象, 实现 ITeacher接口, 组合 ITeacher类
class TeacherProxy implements ITeacher {

    private ITeacher target;

    public TeacherProxy(ITeacher target) {
        this.target = target;
    }

	// 通过成员属性target目标对象 来调用teach方法, 在执行teach方法前后 扩展目标对象的功能
    @Override
    public void teach() {
        System.out.println("开始代理...");
        target.teach();
        System.out.println("代理结束...");
    }

}

测试:

public class StaticProxyPattern {

    public static void main(String[] args) {
        // 目标对象
        ITeacher target = new Teacher();
        // 代理对象, 将目标对象传递给代理对象
        TeacherProxy proxy = new TeacherProxy(target);
        // 代理对象通过目标对象执行teach方法, 且在执行方法前可对目标对象的扩展功能
        proxy.teach();
    }
}

在这里插入图片描述
静态代理的优缺点:

  • 优点: 在不修改目标对象的功能前提下, 能通过代理对象对目标对象的功能扩展
  • 缺点: 代理对象需要和目标对象实现了同一接口, 会存在很多代理类. 且 一旦接口增加方法, 目标对象与代理对象都要维护


动态代理: 代理对象不需要实现接口, 但目标接口一定要实现接口(否则不能使用动态代理), 代理对象由JDK的API(反射), 动态的在内存中创建代理对象. 动态代理又因此称之为: JDK代理、接口代理

JDK中生成代理对象的API: java.lang.reflect.Proxy.newProxyInstance(ClassLoader, Class<?>[], InvocationHandler) 方法, 方法返回一个代理对象(Object), 该方法接受三个参数:

  • ClassLoader laoder: 目标对象(被代理对象)的类加载器, 对生成的代理对象进行加载
  • Class<?>[] interfaces: 目标对象(被代理对象)实现的接口类型数组, 生成的代理对象会实现这些接口
  • InvocationHandler 接口: 调用处理器接口, 只有一个抽象方法 invoke(Object, Method, Object[]), 当调用执行代理对象的方法时, 会转发到的 InvocationHandler.invoke 方法来执行, 且会将目标对象和目标对象的方法作为参数传递, invoke 返回值是 Object (执行方法后返回的对象)
    • Object proxy: 目标对象(被代理的对象)
    • Method method: 调用目标对象的方法Method
    • Object[] args: 调用目标对象方法时接受的参数

在这里插入图片描述

public class DynamicProxyPattern {
    public static void main(String[] args) {
        // 创建目标对象(被代理对象)
        Teacher teacher = new Teacher();
        
        // 给目标对象创建代理对象
        ProxyFactory proxyFactory = new ProxyFactory(teacher);

        // 放回的代理对象是Object类型, 由于指定了目标对象实现的接口, 导致代理对象也实现了此接口, 强转
        ITeacher proxy = (ITeacher) proxyFactory.getProxyInstance();
        System.out.println("代理对象的类型: " + proxy.getClass());
        proxy.teach();
    }

}

interface ITeacher {
    void teach();
}

class Teacher implements ITeacher {

    @Override
    public void teach() {
        System.out.println("教师正在授课...");
    }
}

class ProxyFactory {
    private Object target; // 目标对象, 被代理的对象

    public ProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 通过 java.lang.reflect.Proxy.newProxyInstance() 方法生成代理对象实例
     *
     * @return
     */
    public Object getProxyInstance() {

        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("JDK动态代理, 在目标方法执行之前扩展功能");

                /*
                    method.invoke(Object obj, Object... args): 执行目标对象(被代理对象)的方法, 方法返回Object
                    obj: 目标对象实例, 由这个实例去执行方法
                    args: 执行这个方法需要的参数数组
                 */
                Object invoke = method.invoke(target, args);

                System.out.println("JDK动态代理, 在目标方法执行之后扩展功能");
                return invoke;
            }
        });
    }
}

测试
在这里插入图片描述



Cglib代理: Cglib代理是可以对没有实现接口的类产生代理对象, 是在内存中, 通过继承目标类来产生代理对象, 因此也称之为子类代理.

Cglib是一个强大的高性能的代码生成包(需要引入), 它广泛运用于AOP的框架中, 如 Spring AOP. 底层通过字节码处理框架ASM来转换字节码并生成代理类, final修饰的类, 无法继承; final修饰的方法, 无法覆盖重写

引入jia包: asm-7.0-beta.jar、asm-commons-7.0-beta.jar、asm-util-7.0-beta.jar、cglib-3.1.jar

在这里插入图片描述

public class CglibProxyPattern {
    public static void main(String[] args) {
        // 创建目标对象(被代理对象)
        Teacher teacher = new Teacher();
        // 给目标对象创建代理对象
        ProxyFactory proxyFactory = new ProxyFactory(teacher);
		// 放回的代理对象是Object类型, 由于Enhancer设置父类类型, 导致代理对象也继承了此父类, 强转
        Teacher proxy = (Teacher) proxyFactory.getProxyInstance();
        System.out.println("代理对象的类型: " + proxy.getClass());
        System.out.println();
        proxy.teach();
    }
}

interface ITeacher {
    void teach();
}

class Teacher implements ITeacher {

    @Override
    public void teach() {
        System.out.println("教师正在授课...");
    }
}

/**
 * 代理工厂实现 MethodInterceptor 接口生成方法拦截器intercept方法
 */
class ProxyFactory implements MethodInterceptor {

    private Object target; // 目标对象, 被代理的对象

    public ProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 通过 Cglib 生成代理对象实例
     * @return
     */
    public Object getProxyInstance() {
        // 1.创建 Enhancer对象, 创建代理类
        Enhancer enhancer = new Enhancer();
        // 2.设置父类类型, 生成的代理对象继承父类类型
        enhancer.setSuperclass(target.getClass());
        // 3.设置回调函数
        enhancer.setCallback(this);
        // 4. 创建代理子对象
        return enhancer.create();
    }

	/**
     *  方法拦截器, 类似JDK代理的InvocationHandler接口实现类
     * 		当调用执行代理对象的方法时, 会转发到的 intercept 方法来执行, 且会将目标对象和目标对象的方法作为参数传递
     * 		intercept 返回值是 Object (执行方法后返回的对象)
     * 
     * @param o				目标对象
     * @param method		调用目标对象的方法Method
     * @param args			调用目标对象方法时接受的参数
     * @param methodProxy	代理对象
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib动态代理, 在目标方法执行之前扩展功能");
        Object ret = method.invoke(target, args);
        System.out.println("Cglib动态代理, 在目标方法执行之后扩展功能");
        return ret;
    }
}

测试:
在这里插入图片描述

(七) 适配器模式

可以看博主另一篇文章: 适配器模式之3种实现方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值