当前位置:首页>编程知识库>后端开发知识>设计模式
设计模式
阅读 5
2022-11-30

1、什么是设计模式

设计模式为软件设计中出现的常见问题提供了通用的可重用解决方案。该模式通常显示类或对象之间的关系和交互。
模式是解决软件设计中常见问题的工具包。他们定义了一种通用语言,可帮助您的团队更有效地沟通。分类设计模式的复杂性、详细程度和适用范围各不相同。

2、常用的设计模式

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

3、开发中常用的设计模式

单例、工厂、代理、模板、原型(clone)、观察者(MQ订阅)

3.1、单例

3.1.1 懒汉模式

package com.jy.lejutaobao.testDemo;

/**
 * 懒汉单例模式 多种实现
 */
public class SingleLazy {
    private static SingleLazy instance=null;
    private SingleLazy() {}
    /**
     * 方式一
     * 线程不安全
     * @return
     */
    public static SingleLazy getNoSafeInstance(){
        if(instance == null){
            instance = new SingleLazy();
        }
        return instance;
    }
        /**
        * 方式二,线程安全
        * @return
        */

    public static synchronized SingleLazy getSafeInstance(){
        if(instance == null){
            instance = new SingleLazy();
        }
        return instance;
    }

    /**
     * 方式三 线程安全
     * 双重检查
     * @return
     */
    public static  SingleLazy getSafeInstance2(){
        //第一次检查
        if(instance == null){
            // 假设多个线程同时执行到synchronized(SingleLazy.class)这一行,则第二次检查来防止重复new对象
            synchronized (SingleLazy.class){
                //第二次检查
                if(instance == null) {
                    instance = new SingleLazy();
                }
            }
        }
        return instance;
    }

    /**
     * 方式四
     * 使用关键字volatile修饰保证有序性和可见性,禁止CPU指令重排
     */
    private static volatile SingleLazy instance2=null;
    public static SingleLazy getSafeInstance3(){
        //第一次检查
        if(instance2 == null){
            // 假设多个线程同时执行到synchronized(SingleLazy.class)这一行,则第二次检查来防止重复new对象
            synchronized (SingleLazy.class){
                //第二重检查
                if(instance2 == null) {
                    instance2 = new SingleLazy();
                }
            }
        }
        return instance2;
    }
    
}

3.1.2 恶汉模式

public class Singleton
{
    private static Singleton instance=new Singleton();
    private Singleton(){}
    public static Singleton getInstance() {
        return instance;
    }
}

3.1.3 推荐使用单例模式 静态内部类

类的静态属性只会在第一次加载类的时候初始化,JVM帮助我们保证了线程的安全性。
public class SingleBest {

    //私有构造方法
    private SingleBest() {}
    //静态内部类
    private static class SingletonBestHolder {
        //静态初始化
        private static SingleBest instance = new SingleBest();
    }

    //获得对象实例
    public static SingleBest getInstance() {
        return SingletonBestHolder.instance;
    }
}

4、工厂模式

工厂模式分为普通工厂模式和抽象工厂模式
public abstract class AbstractFactory {
    abstract CarDTO createCarDTO(int type);
}
Public Factory1 extend AbstractFactory{
   CarDTO createCarDTO(int a){
     Switch(a){
     Case 1:new CarDTO1();
     Case 2:new CarDTO2();
}
}
}
普通工厂模式:生产具体的产品,创建的产品是类(Class)。
抽象工厂模式:生产抽象的产品,创建的产品是接口(Interface)。

5、建设者模式

1.定义一个生产电脑的抽象类 里面定义生成电脑需要的CPURAM(内存),Motherboard(主板),HardDisk(硬盘),显示器(Display
2.定义一个电脑对象,一台电脑包括基本的需要的硬件,CPU,内存,主板,硬盘,显示器
/*生产电脑的抽象类*/
public abstract class ComputerBuilder {
    protected Computer computer=new Computer();
    public abstract void buildBrand();
    public abstract void buildCpu();
    public abstract void buildRam();
    public abstract void buildMotherboard();
    public abstract void buildHardDisk();
    public abstract void buildDisplay();


    public Computer getComputer() {
        return computer;
    }
}
public class Computer {
    private String brand;
    private String cpu;
    private String ram;
    private String motherboard;
    private String hardDisk;
    private String display;

    public Computer() {
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getCpu() {
        return cpu;
    }

    public void setCpu(String cpu) {
        this.cpu = cpu;
    }

    public String getRam() {
        return ram;
    }

    public void setRam(String ram) {
        this.ram = ram;
    }

    public String getMotherboard() {
        return motherboard;
    }

    public void setMotherboard(String motherboard) {
        this.motherboard = motherboard;
    }

    public String getHardDisk() {
        return hardDisk;
    }

    public void setHardDisk(String hardDisk) {
        this.hardDisk = hardDisk;
    }

    public String getDisplay() {
        return display;
    }

    public void setDisplay(String display) {
        this.display = display;
    }

    @Override
    public String toString() {
        return "Computer{"  
                "brand='"   brand   '\''  
                ", cpu='"   cpu   '\''  
                ", ram='"   ram   '\''  
                ", motherboard='"   motherboard   '\''  
                ", hardDisk='"   hardDisk   '\''  
                ", display='"   display   '\''  
                '}';
    }
}
3.定义两个建造者分别继承上面的抽象类(ComputerBuilder) ,两个建造者分别是生产华硕电脑和联想电脑。
public class ASUSComputerBuilder extends ComputerBuilder{
    @Override
    public void buildBrand() {
        computer.setBrand("ASUS");
    }

    @Override
    public void buildCpu() {
        computer.setCpu("Intel 酷睿 i9 13900K");
    }

    @Override
    public void buildRam() {
        computer.setRam("金士顿骇客神条FURY 16GB DDR4 3200(HX432C18FB/16-SP)");
    }

    @Override
    public void buildMotherboard() {
        computer.setMotherboard("华硕TUF GAMING B660M-PLUS WIFI D4 供电模式:10 1相 主芯片组:Intel B6");
    }

    @Override
    public void buildHardDisk() {
        computer.setHardDisk("希捷BarraCuda 2TB 7200转 256MB SATA3(ST2000DM008) 台式机械硬");
    }

    @Override
    public void buildDisplay() {
        computer.setDisplay("飞利浦279C9 4K显示器,支持HDR400,65W反向充电,四边微边设计");
    }
}
public class LenoveoComputerBuilder extends ComputerBuilder{

    @Override
    public void buildBrand() {
        computer.setBrand("Lenovo");
    }

    @Override
    public void buildCpu() {
        computer.setCpu("Intel 酷睿 i9-13900KF");
    }

    @Override
    public void buildRam() {
        computer.setRam("联想16GB DDR4 2666 ");
    }

    @Override
    public void buildMotherboard() {
        computer.setMotherboard("技嘉B660M GAMING DDR4 主芯片组:Intel B660 CPU插槽:LGA 1700 内存类");
    }

    @Override
    public void buildHardDisk() {
        computer.setHardDisk("三星980 PRO NVMe M.2 TLC闪存架构,NVMe M.2接口,Elpis控制器");
    }

    @Override
    public void buildDisplay() {
        computer.setDisplay("联想TE24-20 ");
    }
}
4、定义一个指挥者。方法获电脑产品,入参是上面的抽象类,方法里是执行生产电脑的每一个步骤。
public class ComputerDirector {
    private ComputerBuilder computerBuilder;
    private Computer computer;
    public void setComputerBuilder(ComputerBuilder computerBuilder) {
        this.computerBuilder = computerBuilder;
    }
    public Computer getComputer() {
        computerBuilder.buildBrand();
        computerBuilder.buildCpu();
        computerBuilder.buildRam();
        computerBuilder.buildMotherboard();
        computerBuilder.buildHardDisk();
        computerBuilder.buildDisplay();
        return computerBuilder.getComputer();
    }

    public static void main(String[] args) {

        ComputerDirector computerDirector=new ComputerDirector();

        ASUSComputerBuilder asusComputerBuilder=new ASUSComputerBuilder();

        LenoveoComputerBuilder lenoveoComputerBuilder=new LenoveoComputerBuilder();

        /**
         * 让华硕电脑建造者制造电脑
         */
        computerDirector.setComputerBuilder(asusComputerBuilder);

        /**
         * 获得华硕电脑
         */
        Computer computerAsus=computerDirector.getComputer();
        System.out.println(computerAsus);


        /**
         * 让联想电脑建造者制造电脑
         */
        computerDirector.setComputerBuilder(lenoveoComputerBuilder);
        /**
         * 获得联想电脑
         */
        Computer computerLenovo=computerDirector.getComputer();
        System.out.println(computerLenovo);

    }

}
好处:每个具体的创建者是互相独立的。 客户端不需要感知内部实现细节。
坏处: 每个创建者的结构需要是统一的,往往限制了使用。

6、代理模式

代理模式分静态代理和动态代理

静态代理:步骤

1. 创建一个接口A
2. 创建一个被代理的类C1实现接口A
3. 创建一个代理类C2 实现接口A 方法中用C1去调用接口.

代码如下:
 /**
     * 创建一个接口A
     **/

public interface A {
    void doSomething();
}
 /**
     *创建一个被代理的类C1实现接口A
     **/

public class C1  implements A{
    @Override
    public void doSomething() {
        System.out.println("我要买电脑");
    }
}
 /**
     *创建一个代理类C2 实现接口A 方法中用C1去调用接口.
     **/
public class C2  implements A{
    private C1 c1=new C1();
    @Override
    public void doSomething() {
        doBefore();
        c1.doSomething();
        doAfter();
    }


    /**
     * 前置服务
     **/
    public void doBefore(){
        System.out.println("-----进行前置服务-----");
    }

    /**
     * 后置服务
     **/
    public void doAfter(){
        System.out.println("-----进行后置服务-----");
    }
}

动态代理:步骤

1、创建接口定义Subject
2、创建被代理类SubjectImpl 实现接口Subject
3、创建动态代理类
代码如下
/**
 * 1、创建接口定义Subject
 */
public interface Subject {
    void sellPhone();
}

/**
 * 2、创建被代理类SubjectImpl 实现接口Subject
 */
public class SubjectImpl implements Subject{
    @Override
    public void sellPhone() {
        System.out.println("买华为手机");
    }
}

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 3、创建动态代理类
 */
public class SubjectProxy  implements InvocationHandler {
    private Subject subject;

    public SubjectProxy(Subject subject) {
        this.subject = subject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doBefore();
        Object invoke = method.invoke(subject, args);
        doAfter();
        return invoke;
    }


    public  Object getInvokeHandler() {
        return Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), this);
    }

    /**
     * 前置服务
     **/
    public void doBefore(){
        System.out.println("-----进行前置服务-----");
    }

    /**
     * 后置服务
     **/
    public void doAfter(){
        System.out.println("-----进行后置服务-----");
    }
}


/**
 * 测试动态代理
 */
public class TestSubjectDemo {
    public static void main(String[] args) {
        SubjectImpl subject = new SubjectImpl();
        SubjectProxy subjectProxy = new SubjectProxy(subject);
        Subject proxyInstance = (Subject)subjectProxy.getInvokeHandler();
        proxyInstance.sellPhone();
    }
}

7、模板设计模式

定义一套骨架,把共用的部分放在抽象类里实现,不同的部分放到子类中实现并继承抽象类;
好处是: 可以把共同点抽取出来,不同点进行抽象和扩展。
坏处是: 有可能会创建出很多和子类,使代码过于庞大。

8、装饰模式

通过抽象类和类和类的继承对方法进行加工。其实就是添加新功能,添加扩展点。

9、设计模式六大原则

9.1 单一职责原则

一个类只负责一个功能领域中的相应职责。
比如加解密类 定义加密方法和解密方法,和数据传输方法。那么数据传输方法就领域的职责就不一样,需要分开。

9.2 开闭原则 OCP

定义:一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展
比如后期有功能扩展,为了避免修改原有代码,可以在基础上加扩展。通过抽象类和子类的方式实现
如何使用开闭原则
1).抽象类、接收
2).插件、组件方式引用

9.3 里氏替换原则

因为继承带来的侵入性,增加了耦合性,也降低了代码灵活性,父类修改代码,子类也会受到影响,此时就需要里氏替换原则。
public class A {
    public void fun(int a,int b){
        System.out.println(a " " b "=" (a b));
    }
}
 
public class B extends A{
    @Override
    public void fun(int a,int b){
        System.out.println(a "-" b "=" (a-b));
    }
}

9.4 依赖倒置

依赖倒置的意思,就是说要程序依赖于抽象接口,而不是依赖于具体实现,把对具体实现的依赖转移到了抽象接口

9.5 接口隔离原则

使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

9.6 迪米特法则

最少知识原则。一个软件实体应当尽可能少地与其他实体发生相互作用。
上一篇: Java多线程
下一篇:Java的Jvm gc
评论 (0)