solitaryclown

设计模式

2022-03-05
solitaryclown

1. 设计模式

1.1. OOP设计原则

1.1.1. S.O.L.I.D

  • S: Single-responsibility principle,单一职责原则
    程序中的每个模块、每个类、每个函数都应该只完成一项功能,保证功能单一。 一个类应该只有一个理由去改变它,那就是我们想要改变这个类的单一功能。

    遵循SRP的好处:使封装变得更容易;功能出错时只需要找到这个负责这个功能的部分。

  • O: Open-closed principle,OCP,开闭原则
    open for extension,closed for modification,即对扩展开放、对修改关闭。 程序应该对新功能的扩展开放,并且不需要修改原来的代码。 OCP原则通常依赖于继承/实现机制。

  • L: Liskov substitution principle,里氏替换原则
    由Barbara Liskov在1987年提出,此原则指出:任何父类出现的地方都应该可以用其子类直接替换而不会导致程序错误。

  • I: Interface segregation principle,接口隔离原则
    类应该只具有对其功能执行有用的行为,不应该具有它不会使用的行为,即一个类在实现接口功能时不应该强迫它继承它不需要的方法。 “Many client-specific interfaces are better than one general-purpose interface”,多个特定于client的接口比一个通用的接口要更好

  • D: Dependency inversion principle,依赖倒转原则
    此原则指出:

    1. 高层模块不应该依赖于低层模块,两者都应该依赖抽象
    2. 抽象不应该依赖于细节,细节(实现)应该依赖于抽象 DIP的核心是面向接口编程,这里的接口既指interface又指abstract class,程序中的所有依赖都应该针对抽象而不应该依赖于具体的实现。

    如下面两张图所示: br0phn.png br0Qc6.png

1.1.2. 迪米特法则

Law of Demeter,又叫最少知识原则,一个类应该对其他类有尽可能少的了解,一个软件实体应该和其他实体有尽可能少的相互作用——“talk only to your immediate friends”。

1.1.3. 合成复用原则

Composition/Aggregate Reuse Principle,CARP.
尽量使用组合、聚合和关联来实现类之间的联系,其次考虑继承/实现关系,新的类应该首选委托来重用已有的函数而不是继承。

1.2. 设计模式分类

bBSI39.png

1.2.1. 创建者模式

用于描述“如何创建对象”,主要特点是将对象的创建和使用分离,主要分为5种。

1.2.1.1. 单例模式

单例模式主要的应用场景是对于某个类系统只需要一个全局实例,那么就可以使用单例模式保来设计这个类, 很多种单例的实现方式,比如懒汉式、饿汉式、静态内部类懒加载式、枚举类式。

在讲解这几种单例模式之前,补充一点前置知识:
Q:什么是类的初始化?类在什么时候初始化?
A:类的初始化过程包括给静态变量分配空间并赋值、执行static代码块,这些操作被封装成<clinit>方法,只能由JVM执行。类的初始化是懒惰的,只有下列情况发生时才会进行初始化: 1. 当前类是main()函数所在类 2. 使用new关键字实例化 3. 使用反射访问类 4. 首次访问静态属性、静态方法 5. 子类初始化时先初始化父类

类的初始化

1.2.1.1.1. 懒汉式

在第一次使用这个类的实例时才进行实例化:

        /**
    * 多线程不安全的懒汉式单例模式
    * @author Administrator
    *
    */
    class LazySingleton{
        /**
        * 将构造方法设置成私有,防止外部使用new创建实例
        */
        private LazySingleton() {
            
        }
        private static LazySingleton instance;
        public static LazySingleton getInstance() {
            if(instance==null) {
                instance=new LazySingleton();
            }
            return instance;
        }
    }
    /**
    * 多线程安全的懒汉单例模式(double checked locking,双重检查机制)
    * @author Administrator
    *
    */
    class SafeLazySingleton{
        private SafeLazySingleton() {
            
        }
        /**
        * volatile防止"instance=new SafeLazySingleton();"这段代码的可能由指令重排序引起的问题
        */
        private volatile static SafeLazySingleton instance;
        public static SafeLazySingleton getInstance() {
            if(instance==null) {
                synchronized (SafeLazySingleton.class) {
                    if(instance==null) {
                        instance=new SafeLazySingleton();
                    }
                }
            }
            return instance;
        }
    }

总结:

  1. 在上述的线程安全的懒汉式单例模式中使用了双重检查机制来保证线程安全问题,相比于用synchronized粗暴地保证整个getInstance()方法的原子性,这种方式避免了每次调用该方法都会进行加锁,提高了并发访问的效率。
  2. 同时可以看到对instance变量使用了volatile关键字,它的作用是防止字节码重排序,考虑到这种情况:instance的初始化和赋值是两条字节码指令,可能出现字节码重排序,即先给instance赋值了对象的堆空间地址,再进行初始化,如果是多线程情况下可能出现一个线程在外层的if语句判断instance不为null但内存空间还未进行初始化的情况,此时会使用一个未初始化的对象。volatile保证了instance的写操作(赋值)一定在最后执行,且会把最新的值刷回主存,防止上述情况。
  3. 懒汉式不能防止反射破坏单例
1.2.1.1.2. 饿汉式

类加载时就进行实例化。

/**
 * 饿汉式单例模式,类加载时就创建对象
 * 
 * @author Administrator
 * 
 *
 */
class HungrySingleton implements Serializable {


    /**
     * 
     */
    private static final long serialVersionUID = 9111818045459284114L;

    private HungrySingleton() {
        // 防止反射破坏单例,饿汉式由于类加载就会对实例初始化,无论何时使用反射都会抛出异常。
        if (instance != null) {
            throw new RuntimeException("单例类,不能创建多个实例!");
        }
    }

    private static HungrySingleton instance = new HungrySingleton();

    public static HungrySingleton getInstance() {
        return instance;
    }

    // 方法签名固定,访问修饰符随意,用来进行对象反序列化时保证不破坏单例

    Object readResolve() throws ObjectStreamException {
        return instance;
    }
}
1.2.1.1.3. 静态内部类懒加载式

/**
 * 静态内部类懒加载方式实现单例模式
 * 
 * @author Administrator
 *
 */
class InnerclassSingleton  implements Serializable{
    
    /**
     * 
     */
    private static final long serialVersionUID = 8806276011949329939L;

    private static class InnerClassHolder {
        private static InnerclassSingleton instance = new InnerclassSingleton();
    }

    private InnerclassSingleton() {
        if(InnerClassHolder.instance!=null) {
            throw new RuntimeException("此类为单例类,无法创建多个实例!");
        }
    }

    public static InnerclassSingleton getInstance() {
        return InnerClassHolder.instance;

    }

    //方法签名固定,访问修饰符随意,用来进行对象反序列化时保证不破坏单例
    
    Object readResolve() throws ObjectStreamException{
        return InnerClassHolder.instance;
    }
}
1.2.1.1.4. 枚举类式

枚举类是单例的,且天然防止反射入侵,参考这个方法源码:java.lang.reflect.Constructor.newInstance(Object...)

public class EnumSingletonTest {

    public static void main(String[] args) {
        EnumSingleton instance1 = EnumSingleton.INSTANCE;
        EnumSingleton instance2 = EnumSingleton.INSTANCE;
        
        System.out.println(instance1.hashCode());
        System.out.println(instance2.hashCode());
    }
}
enum EnumSingleton{
    INSTANCE;
}

1.2.1.2. 原型模式

目的:Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

结构:

b77CAe.png

Object类实现了一种原型模式,提供了一个方法clone()用于克隆实例,就是应用了原型模式。

1.2.1.3. 工厂方法模式

工厂方法模式定义一个创建单个对象的接口,但让子类决定实例化哪个类。工厂方法允许类将实例化延迟到子类,更详细一点,工厂方法定义抽象工厂和抽象产品,如何创建产品与创建什么类型的产品都由子类决定。 bfJUj1.png

public abstract class Factory{
    protected abstract Product createProduct();
    public Product getInstance() {
        Product product = createProduct();
        return product;
    }
}
/**
 * 抽象产品
 * @author Administrator
 *
 */
public interface Product {
    void m();
}

/*
具体产品
*/
public class ProductA implements Product{

    @Override
    public void m() {
        // TODO Auto-generated method stub
        System.out.println("ProductA.");
    }
    
}
/**
 * 具体工厂
 * @author Administrator
 *
 */
public class FactoryA extends Factory {

    @Override
    protected Product createProduct() {
        
        return new ProductA();
    }

}
/**
 * 测试类
 * @author Administrator
 *
 */
public class TestFactoryMethod {
    public static void main(String[] args) {
        Factory factoryA = new FactoryA();
        Product instance = factoryA.getInstance();
        instance.m();
    }
}

1.2.1.4. 抽象工厂模式

抽象工厂模式是一系列工厂方法的组合,提供一个接口来创建一系列相关或依赖的对象,而无需指定它们的具体类。

抽象工厂类图:

bTHnlq.png

1.2.1.5. 建造者模式

目的:Separate the construction of a complex object from its representation so that the same construction process can create different representations. b7rkq0.png

1.2.2. 结构型模式

用于描述如何将类或对象按某种布局组成更大的结构。

1.2.2.1. 代理模式

1.2.2.2. 适配器模式

1.2.2.3. 桥接模式

1.2.2.4. 装饰者模式

1.2.2.5. 外观模式

1.2.2.6. 享元模式

1.2.2.7. 组合模式

1.2.3. 行为型模式

用于描述类或对象之间如何相互写作共同完成单个对象无法单独完成的任务

1.2.3.1. 模板方法模式

1.2.3.2. 策略模式

1.2.3.3. 命令模式

1.2.3.4. 职责链模式

1.2.3.5. 状态模式

1.2.3.6. 观察者模式

1.2.3.7. 中介者模式

1.2.3.8. 迭代器模式

1.2.3.9. 访问者模式

1.2.3.10. 备忘录模式

1.2.3.11. 解释器模式


上一篇 Spring Boot

下一篇 排序算法

Comments

Content