设计模式学习笔记

发布于:2025-06-18 ⋅ 阅读:(15) ⋅ 点赞:(0)

一、定义

        设计模式(Design Pattern是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性可维护性可读性稳健性以及安全性的解决方案。

二、七大原则

2.1、单一职责原则

        对类来说的,既一个类应该只负责一项职责。如类A负责两个不同的职责:职责1、职责2。当职责1需求变更而改变类A时,可能造成职责2执行错误,所以需要将类A的粒度分解为A1、A2。

2.2、接口隔离原则

        客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上。

2.3、依赖倒置原则

        高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖其抽象。依赖倒置的中心思想是面向接口编程。

2.4、里氏替换原则

        所有引用基类的地方必须能透明地使用其子类的对象(继承必须确保基类所拥有的性质在子类中仍然成立)(子类尽可能不要重写父类的方法)。

2.5、开闭原则

        对扩展开放,对修改关闭。

2.6、迪米特法则

        一个类对自己依赖的类知道的越少越好。对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了public方法,不对外泄露任何信息。核心是降低类之间的耦合。

2.7、合成复用原则

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

三、UML

        UML(Unified Modeling Language)统一建模语言,是一种用于软件系统分析和设计的语言工具,它用于帮助软件开发人员进行思考和记录思路的结果。

        UML本身是一套符号的规定,就像数学符号和化学符号一样,这些符号用于描述软件模型中的各个元素之间的关系,比如类、接口、实现、泛化(继承)、依赖、组合、聚合等。

四、设计模式分类

创建型模式:单例模式、工厂方法模式、抽象工厂模式、原型模式、建造者模式

结构性模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式

行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、责任链模式

五、设计模式

5.1、单例模式

5.1.1、介绍

        保证某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。

5.1.2、代码实现

1)、静态常量饿汉式
// 单例模式-饿汉式-静态常量
public class Singleton {
    // 构造器私有化,外部不能new
    private Singleton() {}

    // 本类内部创建对象实例,类加载时就完成实例化
    private final static Singleton instance = new Singleton();

    // 提供一个公有静态的方法,返回实例对象
    public static Singleton getInstance() {
        return instance;
    }
}

优点:写法简单,类加载的时候就完成实例化,避免了线程同步问题

缺点:没有达到懒加载的效果,可能造成内存浪费

2)、静态代码块饿汉式
// 单例模式-饿汉式-静态代码块
public class Singleton {
    // 构造器私有化,外部不能new
    private Singleton() {}

    private final static Singleton instance;

    // 静态代码块中创建对象实例,类加载时就完成实例化
    static {
        instance = new Singleton();
    }
    
    // 提供一个公有静态的方法,返回实例对象
    public static Singleton getInstance() {
        return instance;
    }
}

优点:类加载的时候就完成实例化,避免了线程同步问题

缺点:没有达到懒加载的效果,可能造成内存浪费

3)、线程不安全懒汉式
// 单例模式-懒汉式-线程不安全
public class Singleton {
    // 构造器私有化,外部不能new
    private Singleton() {}

    private static Singleton instance;

    // 提供一个公有静态的方法,返回实例对象
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优点:达到懒加载的效果,但是只能单线程下使用

缺点:线程不安全,实际开发中不要使用

4)、线程安全懒汉式
// 单例模式-懒汉式-线程安全
public class Singleton {
    // 构造器私有化,外部不能new
    private Singleton() {}

    private static Singleton instance;

    // 加入同步代码,保证线程安全
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优点:线程安全

缺点:效率低,实际开发中不推荐

5)、同步代码块懒汉式
// 单例模式-懒汉式-同步代码块-线程不安全
public class Singleton {
    // 构造器私有化,外部不能new
    private Singleton() {}

    private static Singleton instance;
    
    public static Singleton getInstance() {
        if (instance == null) {
            // 同步代码块
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        }
        return instance;
    }
}

缺点:线程不安全,效率也不高,实际开发中不能使用

6)、双重检查懒汉式
// 单例模式-懒汉式-双重检查-线程安全
public class Singleton {
    // 构造器私有化,外部不能new
    private Singleton() {}

    private static Singleton instance;

    public static Singleton getInstance() {
        // 第一次检查
        if (instance == null) {
            // 同步代码块,保证线程安全
            synchronized (Singleton.class) {
                // 第二次检查
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

优点:线程安全、延迟加载、效率较高,实际开发中推荐使用

7)、静态内部类懒汉式
// 单例模式-懒汉式-静态内部类-线程安全
public class Singleton {
    // 构造器私有化,外部不能new
    private Singleton() {}

    // 外部类加载时,静态内部类不会加载,保证懒加载效果
    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        // 类加载,保证线程安全
        return SingletonInstance.INSTANCE;
    }
}

优点:通过类加载机制保证线程安全,利用静态内部类特点实现延迟加载,效率高,推荐使用

8)、枚举
// 单例模式-枚举-线程安全
enum Singleton {
    INSTANCE;
}

优点:线程安全,还能防止反序列化重新创建对象,推荐使用

5.1.3、例子

        jdk中的Runtime类中使用了静态变量饿汉式的单例模式

5.1.4、使用场景

        频繁创建和销毁的对象,创建对象时耗时过多或者耗费资源过多,但是又是经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)

5.2、简单工厂模式

5.2.1、介绍

        通过一个工厂类来集中管理对象的创建逻辑,客户端无需直接实例化具体类,实现对象创建与使用的解耦。简单工厂模式是工厂模式的一种。

5.2.2、代码实现

// 披萨 抽象类
public abstract class Pizza {
    protected String name;
    public abstract void prepare();

    public void bake() {
        System.out.println(name + "baking");
    }
    public void cut() {
        System.out.println(name + "cutting");
    }
    public void box() {
        System.out.println(name + "boxing");
    }
    public void setName(String name) {
        this.name = name;
    }
}
// 希腊披萨类,继承披萨类
public class GreekPizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("希腊披萨准备原材料");
    }
}
// 奶酪披萨类,继承披萨类
public class CheesePizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("奶酪披萨准备原材料");
    }
}
// 简单工厂类
public class SimpleFactory {
    // 提供创建披萨方法
    public Pizza createPizza(String type) {
        System.out.println("使用简单工厂模式");
        Pizza pizza = null;
        if ("greek".equals(type)) {
            pizza = new GreekPizza();
            pizza.setName("希腊披萨");
        } else if ("cheese".equals(type)) {
            pizza = new CheesePizza();
            pizza.setName("奶酪披萨");
        }
        return pizza;
    }

    // 提供创建披萨方法-静态方法
    public static Pizza createPizza2(String type) {
        System.out.println("使用简单工厂模式-静态方法");
        Pizza pizza = null;
        if ("greek".equals(type)) {
            pizza = new GreekPizza();
            pizza.setName("希腊披萨");
        } else if ("cheese".equals(type)) {
            pizza = new CheesePizza();
            pizza.setName("奶酪披萨");
        }
        return pizza;
    }
}
// 披萨店类
public class PizzaStore {
    // 提供披萨下单方法
    public Pizza orderPizza(String type) {
        SimpleFactory simpleFactory = new SimpleFactory();
        Pizza pizza = simpleFactory.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }

    // 提供披萨下单方法
    public Pizza orderPizza2(String type) {
        Pizza pizza = SimpleFactory.createPizza2(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }

    public static void main(String[] args) {
        PizzaStore store = new PizzaStore();
        store.orderPizza("greek");
        store.orderPizza2("cheese");
    }
}

5.2.3、例子

        Calendar类(时间操作类)

5.3、工厂方法模式

5.3.1、介绍

        定义了一个创建对象的抽象方法,由子类决定要实例化的类。将对象的实例化推迟到子类。每个子类都可以实现工厂接口以提供具体的对象实例化过程

5.3.2、代码实现

// 抽象类
public abstract class OrderPizza {
    // 抽象方法,让各个子类工厂区实现具体业务
    public abstract Pizza createPizza();

    public OrderPizza() {
        Pizza pizza = createPizza();
        if (pizza != null) {
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }
    }
}
public class GreekOrderPizza extends OrderPizza {
    @Override
    public Pizza createPizza() {
        Pizza pizza = new GreekPizza();
        pizza.setName("希腊披萨");
        return pizza;
    }
}
public class CheeseOrderPizza extends OrderPizza {
    @Override
    public Pizza createPizza() {
        Pizza pizza = new CheesePizza();
        pizza.setName("奶酪披萨");
        return pizza;
    }
}
// 披萨店类
public class PizzaStore {
    public static void main(String[] args) {
        new CheeseOrderPizza();
        new GreekOrderPizza();
    }
}

5.4、抽象工厂模式

5.4.1、介绍

        提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式允许客户端在不指定具体类的情况下,创建一系列的产品对象。

我的理解:大体上跟工厂方法模式差不多,多了一些抽象方法来创建多种对象。

5.5、原型模式

5.5.1、介绍

        通过复制(克隆)现有对象来创建新对象,而不是通过使用构造函数创建。原型模式的核心思想是基于现有对象创建新的对象,而不是从零开始创建

5.5.2、代码实现

 1)、浅拷贝
public class Sheep implements Serializable, Cloneable {
    private String name;
    private String color;

    public Sheep(String name, String color) {
        this.name = name;
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

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

    @Override
    public String toString() {
        return "Sheep{" + "name='" + name + '\'' + ", color='" + color + '\'' + '}';
    }

    // 克隆
    @Override
    protected Object clone() {
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return sheep;
    }
}
public class Client {
    public static void main(String[] args) {
        Sheep sheep = new Sheep("喜洋洋", "白色");
        Sheep sheep1 = (Sheep) sheep.clone();// 克隆
        Sheep sheep2 = (Sheep) sheep.clone();// 克隆
        System.out.println(sheep.toString());
        System.out.println(sheep1.toString());
        System.out.println(sheep2.toString());
    }
}
2)、深拷贝(clone方法、反序列化)
public class DeepSheep implements Serializable, Cloneable {

    private String name;

    private Sheep sheep;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Sheep getSheep() {
        return sheep;
    }

    public void setSheep(Sheep sheep) {
        this.sheep = sheep;
    }

    @Override
    public String toString() {
        return "DeepSheep{" + "name='" + name + '\'' + ", sheep=" + sheep + '}';
    }


    // 方式1:clone
    @Override
    protected Object clone() {
        Object deep = null;
        try {
            // 完成基本类型克隆
            deep = super.clone();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        // 引用类型克隆
        DeepSheep deepSheep = (DeepSheep) deep;
        deepSheep.sheep = (Sheep) sheep.clone();
        return deepSheep;
    }

    // 方式2:反序列化
    public Object deepClone() {
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            // 序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            // 反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            DeepSheep deepSheep = (DeepSheep) ois.readObject();
            return deepSheep;
        } catch (Exception e) {

        } finally {
            try {
                if (ois != null) {
                    ois.close();
                }
                if (bis != null) {
                    bis.close();
                }
                if (oos != null) {
                    oos.close();
                }
                if (bos != null) {
                    bos.close();
                }
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        return null;
    }
}
public class Client {
    public static void main(String[] args) {
        DeepSheep deepSheep = new DeepSheep();
        deepSheep.setName("懒洋洋");
        Sheep sheep = new Sheep("喜洋洋", "白色");
        deepSheep.setSheep(sheep);

        // 方式1
        DeepSheep deepSheep1 = (DeepSheep) deepSheep.clone();
        System.out.println(deepSheep.toString());
        System.out.println(deepSheep1.toString());
        System.out.println(deepSheep.getSheep() == deepSheep1.getSheep());

        // 方式2
        DeepSheep deepSheep2 = (DeepSheep) deepSheep.deepClone(); 
        System.out.println(deepSheep.toString());
        System.out.println(deepSheep2.toString());
        System.out.println(deepSheep.getSheep() == deepSheep2.getSheep());
    }
}

5.5.3、例子

        Spring中配置bean使用到scope="prototype"配置项,创建bean时会使用原型模式。

5.6、建造者模式

5.6.1、介绍

        建造者模式又叫生成器模式,是一种对象构建模式。
        它可以将复杂对象的建造过程抽象出来,使这个抽象过程的不同实现方法可以构造出不同表现的对象。
        建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。

建造者模式包含以下角色:

Product(产品角色): 要创建的复杂对象。

Builder(抽象建造者):这个接口规定要实现复杂对象的那些部分的创建,并不涉及具体的部件对象的创建。

ConcreteBuilder(具体建造者):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。在构造过程完成后,提供产品的实例。

Director(指挥者): 调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。

5.6.2、代码实现

// 产品 Product
public class House {
    private String base;
    private String wall;
    private String roof;
    public String getBase() {
        return base;
    }

    public void setBase(String base) {
        this.base = base;
    }

    public String getWall() {
        return wall;
    }

    public void setWall(String wall) {
        this.wall = wall;
    }

    public String getRoof() {
        return roof;
    }

    public void setRoof(String roof) {
        this.roof = roof;
    }
}
// 抽象建造者 Builder
public abstract class HouseBuilder {
    protected House house = new House();
    // 建造流程
    public abstract void buildBase();
    public abstract void buildWall();
    public abstract void buildRoof();

    public House buildHouse() {
        return house;
    }
}
// 具体建造者 ConcreteBuilder
public class CommonHouse extends HouseBuilder {

    @Override
    public void buildBase() {
        System.out.println("普通房子打地基");
    }

    @Override
    public void buildWall() {
        System.out.println("普通房子砌墙");
    }

    @Override
    public void buildRoof() {
        System.out.println("普通房子屋顶");
    }
}
// 指挥者 Director
public class HouseDirector {

    HouseBuilder houseBuilder = null;

    public HouseDirector(HouseBuilder houseBuilder) {
        this.houseBuilder = houseBuilder;
    }

    // 建造流程
    public House constructHouse() {
        houseBuilder.buildBase();
        houseBuilder.buildWall();
        houseBuilder.buildRoof();
        return houseBuilder.house;
    }
}
public class Client {
    public static void main(String[] args) {
        CommonHouse commonHouse = new CommonHouse();
        HouseDirector houseDirector = new HouseDirector(commonHouse);
        House house = houseDirector.constructHouse();
    }
}

5.7、适配器模式

5.7.1、介绍

        适配器模式是将一个类的接口转换成另一种接口,让原本接口不兼容的类可以兼容。使得原本不兼容的类能够协同工作。

5.7.2、代码实现

1)、类适配器

        Adapter类通过继承src类,实现dst类接口,完成src->dst的适配。

// 被适配者 src
public class Voltage220V {
    public int output220V() {
        int src = 220;
        System.out.println("电压=" + src + "V");
        return src;
    }
}
// 目标 dst
public interface Voltage5V {
    public int output5V();
}
// 适配器
public class VoltageAdapter extends Voltage220V implements Voltage5V{
    @Override
    public int output5V() {
        int srcV = output220V();
        int dstV = srcV / 44; // 将220V转成5V
        return dstV;
    }
}
public class Phone {
    public void charging(Voltage5V voltage5V) {
        if (voltage5V.output5V() == 5) {
            System.out.println("充电成功");
        } else {
            System.out.println("充电失败");
        }
    }
}
public class Client {
    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.charging(new VoltageAdapter());
    }
}
2)、对象适配器

        Adapter类不再继承src类,而是持有src类的实例。

// 适配器不使用继承被适配器类
public class VoltageAdapter2 implements Voltage5V{
    private Voltage220V voltage220V;// 关联关系-聚合

    public VoltageAdapter2(Voltage220V voltage220V) {
        this.voltage220V = voltage220V;
    }

    @Override
    public int output5V() {
        int dstV = 0;
        if (voltage220V != null) {
            int srcV = voltage220V.output220V();
            dstV = srcV / 44; // 转成5V
        }
        return dstV;
    }
}
public class Phone {
    public void charging(Voltage5V voltage5V) {
        if (voltage5V.output5V() == 5) {
            System.out.println("充电成功");
        } else {
            System.out.println("充电失败");
        }
    }
}
public class Client {
    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.charging(new VoltageAdapter2(new Voltage220V()));
    }
}
3)、接口适配器

        当不需要全部实现接口提供的方法时,可设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以有选择地覆盖父类的某些方法来实现需求。

public interface Interface3 {
    public void operation1();
    public void operation2();
    public void operation3();
    public void operation4();
}
// 默认实现Interface3的方法
public class AbsAdapter implements Interface3{

    @Override
    public void operation1() {}

    @Override
    public void operation2() {}

    @Override
    public void operation3() {}

    @Override
    public void operation4() {}
}
public class Client {
    public static void main(String[] args) {
        AbsAdapter adapter = new AbsAdapter() {
            // 只需要去覆盖我们需要的接口方法
            @Override
            public void operation1() {
                System.out.println("使用operation1方法");
            }
        };
        adapter.operation1();
    }
}

5.8、桥接模式

5.8.1、介绍

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

5.8.2、代码实现

// 接口
public interface Brand {
    public void open();
    public void close();
    public void call();
}
public class XiaoMi implements Brand{

    @Override
    public void open() {
        System.out.println("小米手机-开机");
    }

    @Override
    public void close() {
        System.out.println("小米手机-关机");
    }

    @Override
    public void call() {
        System.out.println("小米手机-打电话");
    }
}
public class Vivo implements Brand{

    @Override
    public void open() {
        System.out.println("Vivo手机-开机");
    }

    @Override
    public void close() {
        System.out.println("Vivo手机-关机");
    }

    @Override
    public void call() {
        System.out.println("Vivo手机-打电话");
    }
}
public abstract class Phone {
    private Brand brand;

    public Phone(Brand brand) {
        this.brand = brand;
    }

    protected void open() {
        this.brand.open();
    }

    protected void close() {
        this.brand.close();
    }

    protected void call() {
        this.brand.call();
    }
}
public class FoldedPhone extends Phone{

    public FoldedPhone(Brand brand) {
        super(brand);
    }

    public void open() {
        super.open();
        System.out.println("折叠手机");
    }

    public void close() {
        super.close();
        System.out.println("折叠手机");
    }

    public void call() {
        super.call();
        System.out.println("折叠手机");
    }
}
public class Client {
    public static void main(String[] args) {
        Phone phone = new FoldedPhone(new XiaoMi());
        phone.open();
        phone.close();
        phone.call();
        System.out.println("-------------------------");
        Phone phone2 = new FoldedPhone(new Vivo());
        phone2.open();
        phone2.close();
        phone2.call();
    }
}

5.9、装饰者模式

5.9.1、介绍

        动态地将新功能附加到对象上。在对象的功能扩展方面,它比继承更有弹性。

5.9.2、代码实现

public abstract class Drink {
    private String des;
    private float price = 0.0f;

    public String getDes() {
        return des;
    }

    public void setDes(String des) {
        this.des = des;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    // 计算费用 子类实现
    public abstract float cost();
}
public class Coffee extends Drink {

    @Override
    public float cost() {
        return super.getPrice();
    }
}
public class EspressoCoffee extends Coffee {

    public EspressoCoffee() {
        setDes("意式浓缩咖啡");
        setPrice(6.0f);
    }
}
public class AmericanoCoffee extends Coffee {

    public AmericanoCoffee() {
        setDes("美式咖啡");
        setPrice(5.0f);
    }
}
public class Decorator extends Drink {

    private Drink drink;

    public Decorator(Drink drink) {
        this.drink = drink;
    }

    @Override
    public float cost() {
        return super.getPrice() + drink.cost();
    }
}
public class Chocolate extends Decorator {

    public Chocolate(Drink drink) {
        super(drink);
        setDes("巧克力");
        setPrice(3.3f);
    }
}
public class Milk extends Decorator {

    public Milk(Drink drink) {
        super(drink);
        setDes("牛奶");
        setPrice(2.3f);
    }
}
public class Client {
    public static void main(String[] args) {
        Drink order = new AmericanoCoffee();
        System.out.println("美式咖啡 * 1,价格" + order.cost());

        order = new Milk(order);
        System.out.println("美式咖啡 * 1 + 牛奶 * 1,价格" + order.cost());

        order = new Chocolate(order);
        System.out.println("美式咖啡 * 1 + 牛奶 * 1 + 巧克力 * 1,价格" + order.cost());
    }
}

5.9.3、例子

        java的IO结构中,FilterInputStream就是一个装饰者

5.10、组合模式

5.10.1、介绍

        组合模式又叫部分整体模式,它创建了对象组的树形结构,将对象组合成树形结构以表示“整体-部分”的层次关系。

5.10.2、代码实现

public abstract class Organ {
    private String name;

    public Organ(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    protected void add(Organ organ) {
        throw new UnsupportedOperationException();
    }

    protected void remove(Organ organ) {
        throw new UnsupportedOperationException();
    }

    protected abstract void print();

}
public class University extends Organ {

    List<Organ> organs = new ArrayList<>();

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

    @Override
    protected void add(Organ organ) {
        organs.add(organ);
    }

    @Override
    protected void remove(Organ organ) {
        organs.remove(organ);
    }

    @Override
    protected void print() {
        System.out.println(super.getName());
        for (Organ o : organs) {
            o.print();
        }
    }
}
public class College extends Organ {

    List<Organ> organs = new ArrayList<>();

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

    @Override
    protected void add(Organ organ) {
        organs.add(organ);
    }

    @Override
    protected void remove(Organ organ) {
        organs.remove(organ);
    }

    @Override
    protected void print() {
        System.out.println(super.getName());
        for (Organ o : organs) {
            o.print();
        }
    }
}
public class Department extends Organ {

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

    @Override
    protected void print() {
        System.out.println(super.getName());
    }
}
public class Client {
    public static void main(String[] args) {
        Organ university = new University("清华大学");

        Organ c1 = new College("计算机学院");
        Organ c2 = new College("信息工程学院");

        c1.add(new Department("计算机科学与技术"));
        c1.add(new Department("软件工程"));
        c2.add(new Department("信息工程"));
        c2.add(new Department("通信工程"));
        university.add(c1);
        university.add(c2);

        university.print();
        c1.print();
        c2.print();
    }
}

5.11、外观模式

5.11.1、介绍

        外观模式也叫过程模式,通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心子系统的内部细节。

5.11.2、代码实现

public class DVD {
    private static DVD instance = new DVD();

    public static DVD getInstance() {
        return instance;
    }

    public void on() {
        System.out.println("DVD播放");
    }

    public void off() {
        System.out.println("DVD关闭");
    }
}
public class Light {
    private static Light instance = new Light();

    public static Light getInstance() {
        return instance;
    }

    public void on() {
        System.out.println("电灯打开");
    }

    public void off() {
        System.out.println("电灯关闭");
    }
}
public class HomeFacade {
    private DVD dvd;
    private Light light;

    public HomeFacade() {
        super();
        this.dvd = DVD.getInstance();
        this.light = Light.getInstance();
    }

    public void ready() {
        System.out.println("准备看DVD");
        dvd.on();
        light.off();
    }

    public void end() {
        System.out.println("看完DVD了");
        dvd.off();
        light.on();
    }
}
public class Client {
    public static void main(String[] args) {
        HomeFacade homeFacade = new HomeFacade();
        homeFacade.ready();
        homeFacade.end();
    }
}

5.12、享元模式

5.12.1、介绍

        享元模式也叫蝇量模式,运用共享技术有效地支持大量细粒度的请求。享元模式经典应用场景就是池技术,String常量池、数据库连接池、缓冲池等都是享元模式的应用。

5.12.2、代码实现

public abstract class WebSite {
    public abstract void use();
}
public class ConcreateWebSite extends WebSite {

    private String type = "";

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

    @Override
    public void use() {
        System.out.println("网站发布形式:" + type);
    }
}
public class WebSiteFactory {

    // 充当池的作用
    private HashMap<String, ConcreateWebSite> pool = new HashMap<>();

    public WebSite getWebSite(String type) {
        if (!pool.containsKey(type)) {
            pool.put(type, new ConcreateWebSite(type));
        }
        return (WebSite) pool.get(type);
    }

    public int getWebSiteCount() {
        return pool.size();
    }
}
public class Client {
    public static void main(String[] args) {
        WebSiteFactory factory = new WebSiteFactory();
        WebSite webSite = factory.getWebSite("新闻");
        webSite.use();
        WebSite webSite2 = factory.getWebSite("博客");
        webSite2.use();
        WebSite webSite3 = factory.getWebSite("博客");
        webSite3.use();

        System.out.println(factory.getWebSiteCount());
    }
}

5.12.3、例子

        Integer中valueOf方法使用了享元模式。-128到127范围内的值都缓存起来了。

5.13、代理模式

5.13.1、介绍

        为一个对象提供一个替身,以控制对这个对象的访问,即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。

        被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象。

        代理模式有不同的形式,主要有两种:静态代理、动态代理(JDK代理、Cglib代理)。

5.13.2、代码实现

1)、静态代理

        静态代理在使用时,需要定义接口或者父类,被代理对象(目标对象)与代理对象一起实现相同的接口或者继承相同的类。

public interface ITeacher {
    void teach();
}
// 目标对象
public class Teacher implements ITeacher{

    @Override
    public void teach() {
        System.out.println("老师教书");
    }
}
// 代理对象
public class TeacherProxy implements ITeacher{

    private ITeacher target;// 目标对象 通过接口聚合

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

    @Override
    public void teach() {
        System.out.println("开始代理");
        target.teach();
        System.out.println("结束代理");
    }
}
public class Client {
    public static void main(String[] args) {
        // 创建目标对象
        Teacher teacher = new Teacher();
        // 创建代理对象,将目标对象传递给代理对象
        TeacherProxy proxy = new TeacherProxy(teacher);
        proxy.teach();
    }
}

优点:在不修改目标对象的功能前提下,通过代理对象对目标功能扩展

缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类。

           一旦接口增加方法,目标对象与代理对象都要维护

2)、动态代理(JDK代理)

        代理对象不需要实现接口,但是目标对象需要实现接口,否则不能使用动态代理。

        代理对象的生成是利用JDK的API,动态在内存中构建代理对象。

public class ProxyFactory {
    private Object target;

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

//    public static Object newProxyInstance(ClassLoader loader,
//                                          Class<?>[] interfaces,
//                                          InvocationHandler h)
    // ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法固定
    // Class<?>[] interfaces:目标对象的实现接口类型,使用泛型方法确认类型
    // InvocationHandler h:事情处理,执行目标方法时,会触发事件处理器,会把当前执行的目标对象方法作为参数传入
    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代理开始");
                    Object returnVal = method.invoke(target, args);
                    System.out.println("JDK代理结束");
                    return returnVal;
                }
            }
        );
    }
}
public class Client {
    public static void main(String[] args) {
        // 创建目标对象
        Teacher teacher = new Teacher();
        // 创建代理对象
        ITeacher proxy = (ITeacher) new ProxyFactory(teacher).getProxyInstance();
        proxy.teach();
    }
}
3)、动态代理(Cglib代理)

        目标对象没有实现任何接口,可通过目标对象的子类来实现代理。

// 目标对象 不需要实现接口
public class Teacher {

    public void teach() {
        System.out.println("老师教书");
    }
}
public class ProxyFactory implements MethodInterceptor {

    private Object target;

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

    public Object getProxyInstance() {
        // 创建一个工具类
        Enhancer enhancer = new Enhancer();
        // 设置父类
        enhancer.setSuperclass(target.getClass());
        // 设置回调函数
        enhancer.setCallback(this);
        // 创建子类对象,即代理对象
        return enhancer.create();
    }

    // 重写intercept方法,会调用目标对象的方法
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib开始代理");
        Object returnVal = method.invoke(target, objects);
        System.out.println("Cglib结束代理");
        return returnVal;
    }
}
public class Client {
    public static void main(String[] args) {
        // 创建目标对象
        Teacher teacher = new Teacher();
        // 创建代理对象
        Teacher proxy = (Teacher) new ProxyFactory(teacher).getProxyInstance();
        proxy.teach();
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到