Java设计模式 -- GOF23

本文详细介绍了Java设计模式中的GOF23模式,包括创建型、结构型和行为型模式。在创建型模式中,讨论了单例、工厂、建造者和原型模式等,特别是单例模式的五种实现方式及其效率测试。结构型模式涵盖了适配器、代理、装饰和组合模式等,强调了代理模式的静态和动态代理实现。在行为型模式中,讲解了模板方法、策略和观察者模式等,深入探讨了每种模式的应用场景和核心思想。
摘要由CSDN通过智能技术生成

一、设计模式分类

• 创建型模式:
– 单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。
• 结构型模式:
– 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模 式。
• 行为型模式:
– 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模 式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。

二、创建型模式

1、单例模式

核心作用:
保证一个类只有一个实例,并且提供一个访问该实例的全局访问点

实现方式:
常见五种单例模式的分类

  1. 懒汉式(线程安全,调用率高,但是,不能延时加载)
  2. 饿汉式(线程安全,调用率不高,但是,可以延时加载)
  3. 双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题,不建议使用)
  4. 静态内部类式(线程安全,调用率高,但是,可以延时加载)
  5. 枚举单例(线程安全,调用率高,不能延时加载)
①饿汉式
/**
 * 测试饿汉式单例
 */
public class SingletonDemo1 {
   

    // 类初始化时,立即加载这个对象,天然线程安全的
    private static final SingletonDemo1 instance = new SingletonDemo1();

    private SingletonDemo1(){
   }

    // 方法没有同步,调用效率高
    public static SingletonDemo1 getInstance(){
   
        return instance;
    }

}
②懒汉式
/**
 * 测试懒汉式单例
 */
public class SingletonDemo2 {
   

    // 类初始化时,不初始化这个对象(延时加载,真正用到时候再创建)
    private static SingletonDemo2 instance;

    private SingletonDemo2() {
   }

    // 方法同步,调用率低
    public static synchronized SingletonDemo2 getInstance(){
   
        if(instance == null){
   
            instance = new SingletonDemo2();
        }
        return instance;
    }

}
③双重检测锁
/**
 * 双重检测锁实现单例模式
 *
 * 这个模式将同步内容下方到if内部,提高了执行的效率 不必每次获取对象时都进行同步,只有第一次才同步 创建了以后就没必要了。
 *
 * 由于编译器优化原因和JVM底层内部模型原因, 偶尔会出问题。不建议使用。
 */
public class SingletonDemo3 {
   

    private static SingletonDemo3 instance = null;

    private SingletonDemo3() {
   }

    public static SingletonDemo3 getInstance() {
   
        if(instance == null) {
   
            SingletonDemo3 sc;
            synchronized (SingletonDemo3.class) {
   
                sc = instance;
                if(sc == null) {
   
                    synchronized (SingletonDemo3.class) {
   
                        if (sc == null) {
   
                            sc = new SingletonDemo3();
                        }
                    }
                    instance = sc;
                }
            }
        }
        return instance;
    }
}
④静态内部类
/**
 * 静态内部类实现方式(也是一种懒加载方式)
 *
 * – 外部类没有static属性,则不会像饿汉式那样立即加载对象。
 * – 只有真正调用getInstance(),才会加载静态内部类。加载类时是线程安全的。
 *    instance是static final 类型,保证了内存中只有这样一个实例存在,而
 *    且只能被赋值一次,从而保证了线程安全性.
 * – 兼备了并发高效调用和延迟加载的优势!
 */
public class SingletonDemo4 {
   

    private SingletonDemo4(){
   }

    private static class SingletonClassInstance{
   
        private static final SingletonDemo4 instance = new SingletonDemo4();
    }

    private static SingletonDemo4 getInstance(){
   
        return SingletonClassInstance.instance;
    }
}
⑤枚举的方式
/**
 * 枚举的方式实现单例模式(没有延时加载)
 * 枚举本身就是单例模式。由JVM从根本上提供保障!避免通过反射和反序列化的漏洞!
 */
public enum SingletonDemo5 {
   

    // 这个枚举元素本身就是单例的
    //定义两个实例,一个表示请求成功,一个表示请求失败
    HTTP_200(200,"请求成功"), HTTP_500(500,"请求失败");

    //枚举和普通的类一样,可以定义属性,构造函数,getter setter,普通方法,
    private Integer code;
    private String msg;

    SingletonDemo5(Integer code, String msg) {
   
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
   
        return code;
    }

    public String getMsg() {
   
        return msg;
    }

    public void setCode(Integer code) {
   
        this.code = code;
    }

    public void setMsg(String msg) {
   
        this.msg = msg;
    }

}

测试代码

public class Client {
   

    public static void main(String[] args) {
   
        SingletonDemo5 instance = SingletonDemo5.HTTP_200;
        System.out.println(instance == SingletonDemo5.HTTP_200);
        System.out.println(instance.getCode());
        System.out.println(instance.getMsg());
    }
反射与反序列化漏洞和解决方案

测试案例

import java.io.ObjectStreamException;
import java.io.Serializable;

/**
 * 测试懒汉式单例
 */
public class SingletonDemo6 implements Serializable {
   

    private static SingletonDemo6 instance;

    private SingletonDemo6() {
   
        // 1.反射漏洞解决方案
        // 通过手动抛出异常,避免通过反射创建多个单例对象!
        if (instance != null) {
   
            throw new RuntimeException("只能创建一个对象");
        }
    }

    public static synchronized SingletonDemo6 getInstance(){
   
        if(instance == null){
   
            instance = new SingletonDemo6();
        }
        return instance;
    }

	// 2.反序列化漏洞解决方案
    //反序列化时,如果对象所在类定义了readResolve(),(实际是一种回调),定义返回哪个对象。
    private Object readResolve() throws ObjectStreamException {
   
        return instance;
    }

}

测试代码

/**
 * 测试反射和反序列化破解单例模式
 */
public class Client2 {
   

    @Test
    public void demoTest1() throws Exception {
   

        SingletonDemo6 s1 = SingletonDemo6.getInstance();
        SingletonDemo6 s2 = SingletonDemo6.getInstance();

        // 通过反射的方式直接调用私有构造器创建对象
        Class<?> cls = Class.forName("com.xcm.singleton.SingletonDemo6");
        Constructor<?> constructor = cls.getDeclaredConstructor();
        constructor.setAccessible(true);

        SingletonDemo6 s3 = (SingletonDemo6) constructor.newInstance();
        SingletonDemo6 s4 = (SingletonDemo6) constructor.newInstance();

        // 通过反序列化的方式构造多个对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
        oos.writeObject(s1);
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
        SingletonDemo6 s5 = (SingletonDemo6) ois.readObject();

        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
        System.out.println(s4);
        System.out.println(s5);
    }
}
各种单例模式效率测试

测试代码

public class Client3 {
   

    public static void main(String[] args) throws InterruptedException {
   

        long start = System.currentTimeMillis();
        int threadNum = 10;
        // 同步辅助类,它允许一个或者多个线程等待
        final CountDownLatch countDownLatch = new CountDownLatch(threadNum);

        for(int i=0; i<threadNum; i++){
   
            new Thread(new Runnable() {
   
                public void run() {
   
                    for (int i=0; i<1000000; i++){
   
                        // Object instance = SingletonDemo4.getInstance();
                        Object instance = SingletonDemo5.HTTP_200;

                    }
                    // 计数减一
                    countDownLatch.countDown();
                }
            }).start();
        }

        // 阻塞当前的线程,直到计数器的值为0
        countDownLatch.await();

        long end = System.currentTimeMillis();

        System.out.println(end-start);
    }

}

结果:
– 单例对象 占用 资源 少,不需要 延时加载:
• 枚举式 好于 饿汉式
– 单例对象 占用 资源 大,需要 延时加载:
• 静态内部类式 好于 懒汉式

2、工厂模式

①简单工厂 / 静态工厂

要点:
• 用来生产同一等级结构中的任意产品(对于新增的产品,需要修改已有的代码)
• 虽然某种程度不符合设计原则,但实际使用最多。

②工厂方法

要点:
• 用来生产同一等级结构中的固定商品(支持增加任意商品)
• 扩展会增加类的数量,从而使复杂度提高
• 不修改已有类的前提下,通过增加新的工厂类实现扩展。

案例:
(1)定义一个生产汽车的接口

public interface Car {
   
    void run();
}

(2)定义东风汽车、长安汽车的实体类

public class DongFengCar implements Car {
   
    public void run() {
   
        System.out.println("东风汽车");
    }
}
public class ChangAnCar implements Car {
   
    public void run() {
   
        System.out.println("长安汽车");
    }
}

(3)定义生产东风汽车、长安汽车的工厂类

public class DongFengFactory {
   
    public static Car createCar(){
   
        return new DongFengCar();
    }
}
public class ChangAnFactory {
   
    public static Car createCar(){
   
        return new ChangAnCar();
    }
}

(4)测试类

public class Client {
   

    public static void main(String[] args) {
   
        Car car1 = ChangAnFactory.createCar();
        Car car2 = DongFengFactory.createCar();
    }

}
③抽象工厂

要点:
• 主要生产产品族,用来一次性生产不同的产品
• 抽象工厂是工厂方法的升级版

案例
(1)定义生产发动机、座椅的接口

public interface Engine {
   
    void run();
}
public interface Seat {
   
    void sleep();
}

(2)实现接口,定义高端发动机、高端座椅的实体类

public class HighEngine implements Engine {
   
    public void run() {
   
        System.out.println("跑的快");
    }
}
public class HighSeat implements Seat {
   
    public void sleep() {
   
        System.out.println("睡觉舒服");
    }
}

(3)定义汽车的接口,汽车包含发动机与座椅

public interface CarFactory {
   
    Engine createEngine();
    Seat createSeat();
}

(4)实现汽车接口,定义高端汽车的工厂类

public class HighCarFactory implements CarFactory {
   
    public Engine createEngine() {
   
        return new HighEngine();
    }

    public Seat createSeat() {
   
        return new HighSeat();
    }
}

(5)测试

public class Client {
   

    public static void main(String[] args) {
   
        CarFactory factory = new HighCarFactory();
        Engine engine = factory.createEngine();
        engine.run();
    }
}

3、构建者模式

本质

– 分离了对象子组件的单独构造(由Builder来负责)和装配(由Director负责)。 从而可以构 造出复杂的对象。这个模式适用于:某个对象的构建过程复杂的情况下使用。
– 由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象; 相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配 算法的解耦,实现了更好的复用

案例
(1)定义一个飞船,飞船包含发动机和逃逸塔两个零件

/**
 * 飞船类
 */
public class AirShip {
   

    private Engine engine;  // 发动机
    private EscapeTower escapeTower;  // 逃逸塔


    public Engine getEngine() {
   
        return engine;
    }

    public void setEngine(Engine engine) {
   
        this.engine = engine;
    }

    public EscapeTower getEscapeTower() {
   
        return escapeTower;
    }

    public void setEscapeTower(EscapeTower escapeTower) {
   
        this.escapeTower = escapeTower;
    }
}


class Engine{
   
    String name;

    public 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值