首页 > 其他分享 >23种设计模式

23种设计模式

时间:2022-11-27 01:01:20浏览次数:40  
标签:23 模式 class public static new 设计模式 LazyMan

23种设计模式

1、了解设计模式

  • 设计模式 是前辈们对代码开发经验的总结, 是解决特定问题的一系列套路, 他不是语法规定, 而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案
  • 1995年,GoF合作出版了《设计模式:可复用面向对象软件的基础》一书,共收录了23种设计模式,从此树立了软件设计模式领域的里程碑,人称GoF设计模式

学习设计模式的意义

  • 设计模式的本质是面向对象设计原则的实际运用, 是对类的封装性, 继承性和多态性以及类的关联关系和组合关系的充分理解
  • 正确使用设计模式具有以下优点:
    • 可以提高程序员的思维能力, 编程能力和设计能力
    • 使程序设计更加标准化, 代码编制更加工程化, 使软件开发效率大大提高, 从而缩短 软件的开发周期
  • 使设计的代码可重用性高, 可读性强, 可靠性高, 灵活性好, 可维护性强

2、GoF 23

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

3、OOP 七大原则

  • 开闭原则: 对扩展开放, 对修改关闭
  • 里氏替换原则: 继承必须确保超类所拥有的性质在子类中仍然成立
  • 依赖倒置原则: 要面向接口编程, 不要面向实现编程
  • 职责原则: 控制类的粒度大小, 将对象解耦, 提高其内聚性
  • 接口隔离原则: 要为各个类建立它们需要的专用接口
  • 迪米特法则: 只与你的直接朋友交谈,不跟"陌生人"说话
  • 合成复用原则: 尽量先使用组合或者聚合等关联关系实现,其次才考虑使用继承关系来实现

4、单例模式

饿汉式、DCL懒汉式,深究

饿汉式

//饿汉式单例
public class Hungry {
    //可能会很费空间
    private byte[] data1 = new byte[1024*1024];
    private byte[] data2 = new byte[1024*1024];
    private byte[] data3 = new byte[1024*1024];
    private byte[] data4 = new byte[1024*1024];

    private Hungry(){

    }

    private final static Hungry HUNGRY= new Hungry();

    public static Hungry getInstance(){
        return HUNGRY;
    }
}

懒汉式

存在多线程并发模式,后面的DCL懒汉式解决并发问题

public class LazyMan {
    
    private LazyMan(){
        System.out.println(Thread.currentThread().getName()+"OK");
    }

    private static LazyMan lazyMan;


    //双重检测锁模式的  懒汉式单例    DCL懒汉式
    public static LazyMan getInstance(){
        if(lazyMan==null){
            lazyMan = new LazyMan();//不是一个原子性操作
        }
        return lazyMan;
    }
    /*
    * 1.分配内存空间
    * 2、执行构造方法,初始化对象
    * 3、把这个对象指向者个空间
    *
    * 123
    * 132 A
    *
    *     B //此时lazyMan还没有完成构造
    *
    * */


    //多线程并发
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                LazyMan.getInstance();
            }).start();
        }
    }
}

DCL懒汉式
注意:synchronized 解决并发问题,但是因为lazyMan = new LazyMan();不是原子性操作(可以分割,见代码注释),可能发生指令重排序的问题,通过volatil来解决

  • Java 语言提供了 volatile和 synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。
  • 原子性就是指该操作是不可再分的。不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作。简而言之,在整个操作过程中不会被线程调度器中断的操作,都可认为是原子性。比如 a = 1;
public class LazyMan {
    
    private LazyMan(){
        System.out.println(Thread.currentThread().getName()+"OK");
    }

    // volatile 禁止指令重排
    private volatile static LazyMan lazyMan;


    //双重检测锁模式的  懒汉式单例    DCL懒汉式
    public static LazyMan getInstance(){
        if(lazyMan==null){
            synchronized (LazyMan.class){//synchronized加锁解决多线程下的问题
                if(lazyMan == null){
                    lazyMan = new LazyMan();//不是一个原子性操作
                }
            }

        }
        return lazyMan;
    }
    /*
    * 1.分配内存空间
    * 2、执行构造方法,初始化对象
    * 3、把这个对象指向者个空间
    *
    * 123
    * 132 A
    *
    *     B //此时lazyMan还没有完成构造
    *
    * */


    //多线程并发
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                LazyMan.getInstance();
            }).start();
        }
    }
}

静态内部类

//静态内部类
public class Holder {

    //构造器私有
    private Holder(){

    }
    public static Holder getInstance(){
        return InnerClass.HOLDER;
    }

    public static class InnerClass{
        private static final Holder HOLDER = new Holder();

    }
}

单例不安全,反射破坏(见注释及main方法中反射破解步骤)

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

//单例懒汉式
//懒汉式单例

public class LazyMan {
    
    //红绿等解决通过反射创建对象(反编译可以破解该方法)
    private static boolean qingjiang = false;
    
    private LazyMan(){
        synchronized (LazyMan.class){
            if (qingjiang==false){
                qingjiang = true;
            }else{
                throw new RuntimeException("不要试图使用反射破坏单例");
            }

        }
        System.out.println(Thread.currentThread().getName()+"OK");
    }

    private volatile static LazyMan lazyMan;//volatile避免指令重排


    //双重检测锁模式的  懒汉式单例    DCL懒汉式
    public static LazyMan getInstance(){
        if(lazyMan==null){
            lazyMan = new LazyMan();//不是一个原子性操作
        }
        return lazyMan;
    }

//反射!
public static void main(String[] args) throws Exception {
    //LazyMan instance = LazyMan.getInstance();
    Field qingjiang = LazyMan.class.getDeclaredField("qingjiang");
    qingjiang.setAccessible(true);

    Constructor<LazyMan> declaredConstructor =LazyMan.class.getDeclaredConstructor(null);
    declaredConstructor.setAccessible(true);//无视私有的构造器
    LazyMan instance1 = declaredConstructor.newInstance();
    qingjiang.set(instance1,false);
    System.out.println(instance1);
    LazyMan instance2 = declaredConstructor.newInstance();

    System.out.println(instance2);

}

    /*
    * 1.分配内存空间
    * 2、执行构造方法,初始化对象
    * 3、把这个对象指向者个空间
    *
    * 123
    * 132 A
    *
    *     B //此时lazyMan还没有完成构造
    *
    * */


    //多线程并发
   /* public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                LazyMan.getInstance();
            }).start();
        }
    }*/
}

枚举: 通过反射破解枚举发现不成功:
1、普通的反编译会欺骗开发者,说enum枚举是无参构造
2、实际enum为有参构造(见后面);
3、通过反射破解枚举会发现抛出异常
Exception in thread “main” java.lang.IllegalArgumentException: Cannot reflectively create enum objects at java.lang.reflect.Constructor.newInstance(Constructor.java:417) at com.ph.single.Test.main(EnumSingle.java:19)

import java.lang.reflect.Constructor;

//enmu是什么?本身也是一个class类
public enum EnumSingle {
    INSTANCE;
    public EnumSingle getInstance(){
        return INSTANCE;
    }
}

class Test{
    public static void main(String[] args) throws Exception {
        
        EnumSingle instance = EnumSingle.INSTANCE;
        
        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
        
        declaredConstructor.setAccessible(true);
        EnumSingle instance2 = declaredConstructor.newInstance();

        //java.lang.NoSuchMethodException: com.ph.single.EnumSingle.<init>()
        System.out.println(instance);
        System.out.println(instance2);

    }
}

通过idea和jdk自带的反编译枚举如下:

通过jad反编译枚举的代码如下

5、工厂模式

  • 作用:

    • 实现了创建者和调用者的分离
    • 详细分类
      • 简单工厂模式
      • 工厂方法模式
      • 抽象工厂模式
  • OOP七大原则

    • 开闭原则: 一个软件的实体应当对扩展开放, 对修改关闭
    • 依赖倒转原则: 要针对接口编程, 不要针对实现编程
    • 迪米特法则: 只与你直接的朋友通信, 而避免和陌生人通信
  • 核心本质

    • 实例化对象不使用new, 用工厂方法代替
    • 将选择实现类, 创建对象统一管理和控制. 从而将调用者跟我们的实现类解耦
  • 三种模式:

    • 简单工厂模式

    • 用来生产统一等级结构中的任意产品(对于增加新的产品,需要复写已有代码)

    • 工厂方法模式

      • 用来生产同一等级结构中的固定产品(支持增加任意产品)
    • 抽象工厂模式

      • 围绕一个超级工厂创建其他工厂, 该超级工厂又称为其他工厂的工厂

1、简单工厂模式

Car

package com.kuang.factory.simple;

public interface Car {
    void name();
}

Tesla

package com.kuang.factory.simple;

public class Tesla implements Car {
    public void name() {
        System.out.println("特斯拉");
    }
}

WuLing

package com.kuang.factory.simple;

public class WuLing implements Car {
    public void name() {
        System.out.println("五菱宏光");
    }
}

CarFactory

package com.kuang.factory.simple;

public class CarFactory {
    //静态工厂模式
    //增加一个新的产品如果不修改代码做不到

    //方法一
    public static Car getCar(String car){
        if (car.equals("五菱宏光")){
            return new WuLing();
        }else if(car.equals("特斯拉")){
            return new Tesla();
        }else return null;
    }

    //方法二
    public static Car getWuLing(){
        return new WuLing();
    }

    public static Car getTesla(){
        return new Tesla();
    }
}

Consumer

package com.kuang.factory.simple;

public class Consumer {

    public static void main(String[] args) {
        //接口,所有实现类
        Car wuLing = new WuLing();
        Car tesla = new Tesla();
        wuLing.name();
        tesla.name();

        wuLing=CarFactory.getCar("五菱宏光");
        tesla=CarFactory.getCar("特斯拉");
        wuLing.name();
        tesla.name();


    }
}

2、工厂方法模式

Car

package com.kuang.factory.method;

public interface Car {
    void name();
}

CarFactory

package com.kuang.factory.method;

public interface CarFactory {
    //工厂方法模式
    Car getCar();
}

Tesla

package com.kuang.factory.method;

public class Tesla implements Car {
    public void name() {
        System.out.println("特斯拉");
    }
}

TeslaFactory

package com.kuang.factory.method;

public class TeslaFactory implements CarFactory {
    public Car getCar() {
        return new Tesla();
    }
}

WuLing

package com.kuang.factory.method;

public class WuLing implements Car {
    public void name() {
        System.out.println("五菱宏光");
    }
}

WuLingFactory

package com.kuang.factory.method;

public class WuLingFactory implements CarFactory {
    public Car getCar() {
        return new WuLing();
    }
}

Consumer

package com.kuang.factory.method;

import com.kuang.factory.simple.CarFactory;
import com.kuang.factory.simple.Tesla;
import com.kuang.factory.simple.WuLing;

public class Consumer {

    public static void main(String[] args) {
        //接口,所有实现类
        Car wuLing = new WuLingFactory().getCar();
        Car tesla = new TeslaFactory().getCar();
        wuLing.name();
        tesla.name();
    }
//结构复杂度: simple
//代码复杂度: simple
//编程复杂度: simple
//管理上的复杂度: simple
//舰据设计原则:工厂方法模式!
//根据实际业务:简单工厂模式!

}

标签:23,模式,class,public,static,new,设计模式,LazyMan
From: https://www.cnblogs.com/smountain/p/16928810.html

相关文章