23种设计模式

23种设计模式

推荐一个比较好的关于设计模式的网站:https://refactoringguru.cn/design-patterns/builder

零、面向对象软件设计SOLID原则

知乎大佬解释七大原则:https://zhuanlan.zhihu.com/p/24614363

1、单一职责原则(Single responsibility principle,缩写为:SRP)

说明:一个类或者模块只负责完成一个职责(A class or module should have a singleresponsibility)。通俗来说就是,一个模块、类、方法不要承担过多的任务。

原则上来说,我们设计一个类的时候不应该设计成大而全的类,要设计粒度小,功能单一的类,如果一个类两个或者两个以上的不相干的功能,那我们就说它未被了单一职责原则,一个将他拆分成多个功能单一,粒度更细的类。

实际软件开发工作中,不必严格遵守原则,可以设计一个粗粒度的类,随着业务的发展,在进行重构。

实际开发中可以按照一下参考意见,进行代码的重构或者设计:

  • 类依赖过多的其他类,或者代码直接依赖关系过于复杂时,不符合高内聚低耦合的设计思想时,就可以考虑对代码进行拆分。
  • 类的名称和实际的功能关系不大或者没有任何关联性的时候,可以更加细粒度的拆分,把无关的功能独立出去。
  • 类的代码函数过多影响可读性和代码维护时,可以对代码进行方法级别的拆分。

2、开闭原则(Open-closed principle,缩写为:OCP)

说明:软件实体(模块、类、方法等)应该对扩展开放、对修改关闭(software entities (modules、classes、functions,etc.)should be open for extension,but closed for modification)。通俗来讲就是添加一个功能应该是在已有的代码基础上进行扩展,而不是修改已有代码。

开闭原则的目的是为了代码的可扩展,并且避免了对现有代码的修改给软件带来风险。可扩展的前提是需要了解到未来的扩展点,那实际软件开发中如何找到所有的可扩展点呢?一下提供了几种参考方案:

  • 如果是业务驱动的系统,需要在充分了解了业务需求的前提下,才能找到对应的扩展点,如果不确定因素过多,需求变化过快,则可以对一些比较确定的,短期内就可会扩展,通过设计扩展点,能明显提升代码的稳定性和开发效率的地方就行设计。
  • 如果是通用型的技术开发,比如开发通用的框架,组件,类库,你需要考虑技术框架将如何被用户使用,考虑功能的升级需要预留的扩展点以及版本之间的兼容问题。
  • 即时对系统的业务或者技术框架有足够的了解,也不一定要设计所有的扩展点。为未来可能发生变化的每个地方都预留扩展点,也会个系统带来极大的复杂度,实现起来工作量也不可小觑。需要综合开发成本,影响范围,实际收益(包括时间和人员成本)等因素进行考虑。

3、里氏替换原则(Liskvo substitution principle,缩写为:LSP)

说明:子类对象能够替换程序中父类对象的任何地方,并且保证原来的程序的逻辑行为不变及正确性不被破坏。

可以利用面向对象编程的多态性来实现,多态和里氏替换原则优点类似,但是他们的关注角度是不一样的,多态是面向对象编程的特性,而里氏替换是一种原则,用来指导继承关系中子类该如何设计,子类的设计要确保在替换父类的时候,不改变原有的程序的逻辑以及不破坏原有的程序的正确性。

具体的实现方式可以理解为,子类在设计的时候,要遵循父类的行为约定。父类定义了方法的行为,子类可以改变方法的内部实现逻辑,但不能改变方法原有的行为约定,如:接口、方法声明要实现的功能,对参数值、返回值、异常的约定,甚至包括注释中所罗列的任何特殊的说明。

4、接口隔离原则(Interface segregation principle,缩写为:ISP)

说明:客户端不应该强迫依赖它不需要的接口。

接口隔离原则的时间可以参考如下方法:

  1. 对于接口来说,如果某个接口承担了与它无关的接口定义,则说明接口违反了接口隔离原则。可以把无关的接口剥离出去。对胖而杂的接口瘦身。
  2. 对于共通的功能来说,应该细分功能点,按需添加,而不是定义一个大而全的接口,让子类去被迫实现。

5、依赖倒置原则(Dependency inversion principle,缩写为:DIP)

说明:高层模块不要依赖底层模块。高层模块和底层模块应该通过抽象来互相依赖。除此之外,抽象不要依赖具体实现细节,具体实现细节依赖抽象。

这个的高层模块,从代码的角度来说就是调用者,底层模块就是被调用者。即调用者不要依赖于具体的实现,而应该依赖抽象,如Spring中的各个Aware,框架依赖于Aware接口具体的实现增加功能,具体的实现通过实现接口来获得功能。而具体的实现与框架并没有直接耦合。

6、迪米特法则(Law Of Demeter)

迪米特法则又称为 最少知道原则,它表示一个对象应该对其它对象保持最少的了解。通俗来说就是,只与直接的朋友通信。

首先来解释一下什么是直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。

对于被依赖的类来说,无论逻辑多么复杂,都尽量的将逻辑封装在类的内部,对外提供 public 方法,不对泄漏任何信息。

7、组合/聚合复用原则 (Composite/Aggregate Reuse Principle)

组合/聚合复用原则就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分; 新的对象通过向这些对象的委派达到复用已有功能的目的。

在面向对象的设计中,如果直接继承基类,会破坏封装,因为继承将基类的实现细节暴露给子类;如果基类的实现发生了改变,则子类的实现也不得不改变;从基类继承而来的实现是静态的,不可能在运行时发生改变,没有足够的灵活性。于是就提出了组合/聚合复用原则,也就是在实际开发设计中,尽量使用组合/聚合,不要使用类继承。

一、单例模式(Singleton)

1、模式定义/应用场景/类图分析

定义

保证一个类只有一个实例,并且提供一个全局的访问点

场景

重量级的对象,不需要多个实例,如线程池,数据库连接池。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YSBSnqqN-1630034734758)(C:\Users\29829\AppData\Roaming\Typora\typora-user-images\image-20210823220935626.png)]

懒汉模式

延迟加载,只有在真正使用的时候,才开始实例化。

  1. 线程安全问题
  2. double check加锁优化
  3. 编译器(JIT),CPU有可能对指令进行重排序,导致使用代尚未初始化的实例,可以通过添加volatile关键字进行修饰,对于volatile修饰的字段,可以防止指令重排序。
class LazySingleton {
    private static volatile LazySingleton instance;

    private LazySingleton() {
    }

    public static LazySingleton getInstance() {
        if (instance == null) {
            synchronized (LazySingleton.class) {
                if (instance == null) {
                    instance = new LazySingleton();
                    // 字节码层面
                    // JIT,CPU
                    // 1、分配空寂
                    // 2、初始化
                    // 3、引用赋值

                    // 他们三步顺序会进行重排序:可能123的顺序,也可能是132的顺序,所以可以在属性上添加volatile关键字
                }
            }
        }
        return instance;
    }
}
饿汉模式

饿汉模式是通过JVM类加载的特性来实现的,类加载的初始化阶段就完成了实例的初始化。本质上就是借助于JVM类加载机制,保证实例的唯一性。

类加载过程:

  1. 加载二进制数据到内存中,生成对应的Class数据结构

  2. 连接:a.验证,b.准备(给类的静态成员变脸赋默认值),c.解析

  3. 初始化:给类的静态变量赋初值

    只有在真正使用对应的类时,才会触发初始化如(当前类时启动类即main函数所在的类,直接进行new操作,访问静态属性,访问静态方法,用反射访问类,初始化一个类的子类等)

class HungrySingleton{
    private static HungrySingleton instance = new HungrySingleton();

    private HungrySingleton(){
    }

    public static HungrySingleton getInstance(){
        return instance;
    }
}
静态内部类
  • 本质上是利用类的价值机制来保证线程安全
  • 只有在实际使用的时候,才会触发类的初始化 ,所以也是懒加载的一种形式
class InnerClassSingleton{

    // 只有当调用类该类的时候才会初始化,在外部类初始化的时候是不会初始化这个内部类的
    private static class InnerClassHolder{
        private static InnerClassSingleton instance = new InnerClassSingleton();
    }

    private InnerClassSingleton(){
    }

    // 只有在调用这个方法的时候才会初始化内部类,因为此时调用了InnerClassHolder.instance
    public static InnerClassSingleton getInstance(){
        return InnerClassHolder.instance;
    }
}
反射攻击实例

大白话就是,反射会通过单例类的无参的构造方法创建一个新的实例,那肯定和本地的实例不是同一个了,因为每次通过反射得到的实例都是新创建出来的对象。

Constructor<InnerClassSingleton> constructor = InnerClassSingleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
InnerClassSingleton singleton = constructor.newInstance();
InnerClassSingleton instance = InnerClassSingleton.getInstance();
System.out.println(instance == singleton);// false
枚举类型
  • 天然不支持反射创建对应的实例,且有自己的发序列机制
  • 利用类加载机制保证线程安全
enum EnumSingleton{
    INSTANCE;

    public void print(){
        System.out.println(this.hashCode());
    }
}

2、字节码知识/字节码指令重排序

反编译字节码文件
javap -v Demo.class

3、类加载机制

类加载的时机
  • 当通过 new 隐式创建实例的时候
  • 通过LoadClass、forName等的显式加载
  • 访问类的静态变量,或者为静态变量赋值
  • 调用类的静态方法
  • 使用反射方式创建某个类或者接口对象的Class对象。
  • 初始化某个类的子类
  • 直接使用java.exe命令来运行某个主类
类加载的过程

我们编写的java文件都是保存着业务逻辑代码。java编译器将 .java 文件编译成扩展名为 .class 的文件。.class 文件中保存着java转换后,虚拟机将要执行的指令。当需要某个类的时候,java虚拟机会加载 .class 文件,并创建对应的class对象,将class文件加载到虚拟机的内存,这个过程被称为类的加载。
在这里插入图片描述

加载

类加载过程的一个阶段,ClassLoader通过一个类的完全限定名查找此类字节码文件,并利用字节码文件创建一个class对象。

验证

目的在于确保class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身的安全,主要包括四种验证:文件格式的验证,元数据的验证,字节码验证,符号引用验证。

准备

为类变量(static修饰的字段变量)分配内存并且设置该类变量的初始值,(如static int i = 5 这里只是将 i 赋值为0,在初始化的阶段再把 i 赋值为5),这里不包含final修饰的static ,因为final在编译的时候就已经分配了。这里不会为实例变量分配初始化,类变量会分配在方法区中,实例变量会随着对象分配到Java堆中。

解析

这里主要的任务是把常量池中的符号引用替换成直接引用

初始化

这里是类记载的最后阶段,如果该类具有父类就进行对父类进行初始化,执行其静态初始化器(静态代码块)和静态初始化成员变量。(前面已经对static 初始化了默认值,这里我们对它进行赋值,成员变量也将被初始化)

类加载器的任务是根据类的全限定名来读取此类的二进制字节流到 JVM 中,然后转换成一个与目标类对象的java.lang.Class 对象的实例,在java 虚拟机提供三种类加载器,引导类加载器,扩展类加载器,系统类加载器。

forName和loaderClass区别
  • Class.forName()得到的class是已经初始化完成的。
  • Classloader.loaderClass得到的class是还没有链接(验证,准备,解析三个过程被称为链接)的。
双亲委派

双亲委派模式要求除了顶层的启动类加载器之外,其余的类加载器都应该有自己的父类加载器,但是在双亲委派模式中父子关系采取的并不是继承的关系,而是采用组合关系来复用父类加载器的相关代码。

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException {
    // 增加同步锁,防止多个线程加载同一类
    synchronized (getClassLoadingLock(name)) {
        // First, check if the class has already been loaded
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else { // ExtClassLoader没有继承BootStrapClassLoader
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }

            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.
                long t1 = System.nanoTime();
                // AppClassLoader去我们项目中查找是否有这个文件,如有加载进来
                // 没有就到用户自定义ClassLoader中加载。如果没有就抛出异常
                c = findClass(name);

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

4、JVM序列化机制

序列化
  • 可以利用指定方法来替换从反序列化流中的数据,如下
InnerClassSingleton instance = InnerClassSingleton.getInstance();

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("testSerializable"));
oos.writeObject(instance);
oos.close();

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("testSerializable"));
InnerClassSingleton object = (InnerClassSingleton)ois.readObject();
ois.close();

System.out.println(instance == object);
反序列化破坏单例模式

序列化会通过反射调用无参数的构造方法创建一个新的对象。所以在反序列化的时候得到的实例和本地的实例不是同一个。这样就破坏了单例的模式。

防止反序列化破坏单例模式

在Serializable给出了这样的解释:

/**
Classes that need to designate a replacement when an instance of it is read from the stream should implement this special method with the exact signature.
   ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
*/
public interface Serializable {
}
// 简单理解就是要在单例类中实现Serializable接口并且实现Object readResolve() throws ObjectStreamException的方法,例如:
class InnerClassSingleton implements Serializable {
    static final long serialVersionUID = 42L;

    // 只有当调用类该类的时候才会初始化,在外部类初始化的时候是不会初始化这个内部类的
    private static class InnerClassHolder{
        private static InnerClassSingleton instance = new InnerClassSingleton();
    }

    private InnerClassSingleton(){
        if (InnerClassHolder.instance != null){
            throw new RuntimeException("单例不允许多个实例!!!");
        }
    }

    // 只有在调用这个方法的时候才会初始化内部类,因为此时调用了InnerClassHolder.instance
    public static InnerClassSingleton getInstance(){
        return InnerClassHolder.instance;
    }

    Object readResolve() throws ObjectStreamException{
        return InnerClassHolder.instance;
    }
}

注意:enum单例类是天然的防止反序列化破坏单例模式的

5、单例模式在源码中的应用

JDK源码中的应用
  • Runtime.java
public class Runtime {
    private static Runtime currentRuntime = new Runtime();
    
    public static Runtime getRuntime() {
        return currentRuntime;
    }

    private Runtime() {}
}
  • Currency.java
public final class Currency implements Serializable {
	
    // Resolves instances being deserialized to a single instance per currency.
	private Object readResolve() {
        return getInstance(currencyCode);
    }

}
Spring源码中的应用
  • DefaultSingletonBeanRegistry.java
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

    
    // 使用三级缓存解决spring中的循环依赖问题
	/** 一级缓存 */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** 二级缓存 */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** 三级缓存 */
	private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
    
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within full singleton lock
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) {
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
								singletonObject = singletonFactory.getObject();
								this.earlySingletonObjects.put(beanName, singletonObject);
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}
    
}
  • ReactiveAdapterRegistry.java
public class ReactiveAdapterRegistry {

    @Nullable
    private static volatile ReactiveAdapterRegistry sharedInstance;
    
    // double check机制
    public static ReactiveAdapterRegistry getSharedInstance() {
		ReactiveAdapterRegistry registry = sharedInstance;
		if (registry == null) {
			synchronized (ReactiveAdapterRegistry.class) {
				registry = sharedInstance;
				if (registry == null) {
					registry = new ReactiveAdapterRegistry();
					sharedInstance = registry;
				}
			}
		}
		return registry;
	}
}
  • ProxyFactoryBean.java
public class ProxyFactoryBean extends ProxyCreatorSupport implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {

    @Nullable
    private Object singletonInstance;
    
    @Nullable
    public Object getObject() throws BeansException {
        this.initializeAdvisorChain();
        if (this.isSingleton()) {
            return this.getSingletonInstance();
        } else {
            if (this.targetName == null) {
                this.logger.info("Using non-singleton proxies with singleton targets is often undesirable. Enable prototype proxies by setting the 'targetName' property.");
            }

            return this.newPrototypeInstance();
        }
    }

    private synchronized Object getSingletonInstance() {
        if (this.singletonInstance == null) {
            this.targetSource = this.freshTargetSource();
            if (this.autodetectInterfaces && this.getProxiedInterfaces().length == 0 && !this.isProxyTargetClass()) {
                Class<?> targetClass = this.getTargetClass();
                if (targetClass == null) {
                    throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
                }

                this.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
            }

            super.setFrozen(this.freezeProxy);
            this.singletonInstance = this.getProxy(this.createAopProxy());
        }

        return this.singletonInstance;
    }

}

二、工厂模式

0、浅谈设计模式

为什么要引入设计模式呢?实际上是为了在项目代码不断的更新迭代的时候更好的扩展功能代码,如果一个项目的代码是不用迭代的(也就是不用修改添加原代码),那么引用设计模式也就没有太大的意义了。换句话说就是当要考虑引入设计模式的时候,一定要考虑项目代码中是否同时存在不变的部分变的部分。只有同时存在这两部分的时候引入设计模式才有意义。

设计模式的7大原则

  • 开放封闭原则 (OCP,Open For Extension, Closed For Modification Principle)
    • 对功能的扩展开放
    • 对源代码的修改封闭
  • 单一职责原则 (SRP,Single Responsibility Principle)
    • 一个类只负责其自己的功能模块
  • 依赖倒置原则 (DIP,Dependence Inversion Principle)
  • 接口隔离原则 (ISP,Interface Segegation Principle)
  • 里氏替换原则 (LSP, Liskov Substitution Principle)
  • 优先使用组合而不是继承原则(CARP,Composite/Aggregate Reuse Principle)
  • 迪米特法则(LOD,Law of Demeter)

1、模式的定义

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使得一个类的实例化延迟到子类。

在这里插入图片描述

2、简单工厂

public class SimpleFactoryTest {
    public static void main(String[] args) {
        Application application = new Application();
        Product product = application.getObject("a");
        if (product != null) {
            product.method();
        }else {
            System.out.println("Product is null");
        }

    }
}

interface Product {
    public void method();
}

class ProductA implements Product {
    public void method() {
        System.out.println("productA.method executed!!!");
    }
}

class ProductB implements Product {
    public void method() {
        System.out.println("productB.method executed!!!");
    }
}

class SimpleFactory {

    public static Product CreateProduct(String type) {
        if ("A".equals(type)) {
            return new ProductA();
        } else if ("B".equals(type)) {
            return new ProductB();
        }

        return null;
    }
}

class Application {
    private Product createProduct(String type) {
        // ... init
        // ...

        return SimpleFactory.CreateProduct(type);
    }

    public Product getObject(String type) {
        Product product = createProduct(type);
        // ...
        return product;
    }
}

3、工厂方法

应用场景
  • 当不知道该使用对象的确切类型的时候。
  • 当希望为库或框架提供扩展其内部之间的方法时。
主要优点
  1. 将具体的产品和创建者解耦
  2. 符合单一职责原则
  3. 符合开闭原则
代码举例
public class FactoryMethod {
    public static void main(String[] args) {
        Application application = new ConcreteProductB();
        Product product = application.getObject();
        if (product != null) {
            product.method();
        }
    }
}

interface Product {
    void method();
}

class ProductA implements Product {
    public void method() {
        System.out.println("productA.method executed!!!");
    }
}

class ProductB implements Product {
    public void method() {
        System.out.println("productB.method executed!!!");
    }
}


abstract class Application {
    // 开闭原则,单一职责原则
    abstract Product createProduct();

    public Product getObject() {
        Product product = createProduct();
        // ...
        return product;
    }
}

class ConcreteProductA extends Application {

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

class ConcreteProductB extends Application {

    @Override
    Product createProduct() {
        // ...
        return new ProductB();
    }
}
在源码中的应用
// 静态工厂方法
Calendar.getInstance();
java.text.numberFormat.getInstance();
java.util.ResourceBundle.getInstance();

// 工厂方法
java.net.URLStreamhandlerFactory;
javax.xml.bind.JAXBContext.createMarsheller;

4、抽象工厂模式

Abstract Factory

模式定义

提供一个创建一系列相关或相互依赖对象的接口,而无需指定他么的具体类

在这里插入图片描述

应用场景

程序需要处理不同的系列的相关产品,但是您不希望他依赖于这些产品的具体类是,可以使用抽象工厂

优点
  • 可以确信你从工厂得到的产品是彼此兼容的。
  • 可以避免具体产品和客户端代码之间的紧密耦合。
  • 符合单一职责原则。
  • 符合开闭原则。
代码举例
public class AbstractFactoryTest {
    public static void main(String[] args) {
        IDatabaseFactory databaseFactory = new OracleDatabaseFactory();

        IConnection connection = databaseFactory.getConnection();
        connection.connection();

        ICommand command = databaseFactory.getCommand();
        command.command();
    }
}


// 变化:mysql  oracle
// 不变:connect command
interface IConnection{
    void connection();
}

class MysqlConnection implements IConnection{

    @Override
    public void connection() {
        System.out.println("MYSQL connected.");
    }
}

class OracleConnection implements IConnection{

    @Override
    public void connection() {
        System.out.println("Oracle connected.");
    }
}

interface ICommand{
    void command();
}

class MysqlCommand implements ICommand{

    @Override
    public void command() {
        System.out.println("MYSQL command.");
    }
}

class OracleCommand implements ICommand{
    @Override
    public void command() {
        System.out.println("Oracle command.");
    }
}

interface IDatabaseFactory{
    IConnection getConnection();
    ICommand getCommand();
}

class MysqlDatabaseFactory implements IDatabaseFactory{
    @Override
    public IConnection getConnection() {
        return new MysqlConnection();
    }

    @Override
    public ICommand getCommand() {
        return new MysqlCommand();
    }
}

class OracleDatabaseFactory implements IDatabaseFactory{
    @Override
    public IConnection getConnection() {
        return new OracleConnection();
    }

    @Override
    public ICommand getCommand() {
        return new OracleCommand();
    }
}
在源码中的应用
java.sql.Connection;
java.sql.Driver;
Connection
public interface Connection  extends Wrapper, AutoCloseable {
    
    Statement createStatement() throws SQLException;

    PreparedStatement prepareStatement(String sql)
        throws SQLException;

    CallableStatement prepareCall(String sql) throws SQLException;

   
    DatabaseMetaData getMetaData() throws SQLException;
    
    // ....
}
Driver
public interface Driver {

     Connection connect(String url, java.util.Properties info)
        throws SQLException;
    
    DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info)
                         throws SQLException;
    
    // ....

}

三、建造者模式

1、模式定义

将一个复杂对象的创建与他的表示分离,使得同样的构造过程可以创建不同的表示

2、应用场景

  • 需要生成的对象具有复杂的内部结构
  • 需要生成的对象内部属性本身相互依赖
  • 与不可变对象配合使用

3、优点

  • 建造者独立,易扩展
  • 便于控制细节风险

4、标准代码举例

标准的建造者模式的代码写法,写起来比较的复杂

package com.jms.tuling.builder;

/**
 * @author Jamison
 * @version 1.0
 * @date 2021/8/24 15:45
 */
public class BuilderTest {
    public static void main(String[] args) {
        // 建造者
        ProductBuilder productBuilder = new SpecialConcreteProductBuilder();
        // 建筑指挥官
        Director director = new Director(productBuilder);
        // 指定原材料,指定建造者去建筑
        Product product = director.makeProduct("pn", "6000", "hs", "part1xxx", "part2xxx", "part3xxx", "part4xxx");
        System.out.println(product);
    }
}

interface ProductBuilder {
    void builderProductName(String productName);

    void builderProductPrice(String productPrice);

    void builderCompanyName(String companyName);

    void builderPart1(String part1);

    void builderPart2(String part2);

    void builderPart3(String part3);

    void builderPart4(String part4);

    Product build();
}

abstract class ConcreteProductBuilder implements ProductBuilder {
    protected String productName;
    protected String productPrice;
    protected String companyName;
    protected String part1;
    protected String part2;
    protected String part3;
    protected String part4;

    @Override
    public void builderProductName(String productName) {
        this.productName = productName;
    }

    @Override
    public void builderProductPrice(String productPrice) {
        this.productPrice = productPrice;
    }

    @Override
    public void builderCompanyName(String companyName) {
        this.companyName = companyName;
    }

    @Override
    public void builderPart1(String part1) {
        this.part1 = part1;
    }

    @Override
    public void builderPart2(String part2) {
        this.part2 = part2;
    }

    @Override
    public void builderPart3(String part3) {
        this.part3 = part3;
    }

    @Override
    public void builderPart4(String part4) {
        this.part4 = part4;
    }

}

class DefaultConcreteProductBuilder extends ConcreteProductBuilder implements ProductBuilder {

    @Override
    public Product build() {
        return new Product(this.productName, this.productPrice, this.companyName, this.part1, this.part2, this.part3, this.part4);
    }
}

class SpecialConcreteProductBuilder extends ConcreteProductBuilder implements ProductBuilder {

    @Override
    public void builderProductName(String productName) {
        productName += "_jamison";
        this.productName = productName;
    }

    @Override
    public Product build() {
        return new Product(this.productName, this.productPrice, this.companyName, this.part1, this.part2, this.part3, this.part4);
    }
}

class Director {
    private ProductBuilder productBuilder;

    public Director(ProductBuilder productBuilder) {
        this.productBuilder = productBuilder;
    }

    Product makeProduct(String productName, String productPrice, String companyName, String part1, String part2, String part3, String part4) {
        productBuilder.builderProductName(productName);
        productBuilder.builderProductPrice(productPrice);
        productBuilder.builderCompanyName(companyName);
        productBuilder.builderPart1(part1);
        productBuilder.builderPart2(part2);
        productBuilder.builderPart3(part3);
        productBuilder.builderPart4(part4);
        return productBuilder.build();
    }
}


class Product {
    private String productName;
    private String productPrice;
    private String companyName;
    private String part1;
    private String part2;
    private String part3;
    private String part4;

    // set... get.... construct...  toString...
}

5、通常用法代码举例

建造者模式一般会这样写,支持链式编程,实现简单

public class BuilderV2Test {
    public static void main(String[] args) {
        Product.Builder builder = new Product.Builder().productName("productNamexxx")
                .productPrice("6001")
                .companyName("hs");

        // ...
        builder.part1("part1xxx");

        Product product = builder.build();
        System.out.println(product);
    }
}

class Product {
    private final String productName;
    private final String productPrice;
    private final String companyName;
    private final String part1;
    private final String part2;
    private final String part3;
    private final String part4;

    public Product(String productName, String productPrice, String companyName, String part1, String part2, String part3, String part4) {
        this.productName = productName;
        this.productPrice = productPrice;
        this.companyName = companyName;
        this.part1 = part1;
        this.part2 = part2;
        this.part3 = part3;
        this.part4 = part4;
    }

    static class Builder {
        private String productName;
        private String productPrice;
        private String companyName;
        private String part1;
        private String part2;
        private String part3;
        private String part4;

        public Builder productName(String productName) {
            this.productName = productName;
            return this;
        }

        public Builder productPrice(String productPrice) {
            this.productPrice = productPrice;
            return this;
        }

        public Builder companyName(String companyName) {
            this.companyName = companyName;
            return this;
        }

        public Builder part1(String part1) {
            this.part1 = part1;
            return this;
        }

        public Builder part2(String part2) {
            this.part2 = part2;
            return this;
        }

        public Builder part3(String part3) {
            this.part3 = part3;
            return this;
        }

        public Builder part4(String part4) {
            this.part4 = part4;
            return this;
        }

        public Product build() {
            // ...
            return new Product(this.productName, this.productPrice, this.companyName, this.part1, this.part2, this.part3, this.part4);
        }

    }

    @Override
    public String toString() {
        return "Product{" +
                "productName='" + productName + '\'' +
                ", productPrice='" + productPrice + '\'' +
                ", companyName='" + companyName + '\'' +
                ", part1='" + part1 + '\'' +
                ", part2='" + part2 + '\'' +
                ", part3='" + part3 + '\'' +
                ", part4='" + part4 + '\'' +
                '}';
    }
}

6、在源码中的应用

RequestMappingInfo类中的使用

org.springframework.web.servlet.mvc.method.RequestMappingInfo类中就是有一个builder;

public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {

    private static class DefaultBuilder implements RequestMappingInfo.Builder {
        // ...
    }
    
    private static class MutateBuilder implements RequestMappingInfo.Builder {
    	// ...
    }

    public interface Builder {
        // ....
    }
}
BeanDefinitionBuilder 类中的使用

org.springframework.beans.factory.support.BeanDefinitionBuilder

public final class BeanDefinitionBuilder {
    // ...
}

四、原型模式

1、知识点

Cloneable接口/Object#clone方法详解

只有当一个类实现了Cloneable接口,才能开启Object.clone方法,

class Product implements Cloneable,Serializable{

	// 重写clone方法
	@Override
    protected Product clone() throws CloneNotSupportedException {
        // 通过Object.clone方法clone实例
        Product product = (Product) super.clone();
        BaseInfo baseInfo = product.getBeasInfo().clone();
        product.setBeasInfo(baseInfo);
        return product;  
    }
}
浅拷贝/深拷贝
  • 浅拷贝

    浅拷贝在拷贝时只会拷贝只会拷贝引用地址,所以拷贝的对象与原对象的引用类型的数据指向的是同一个对象。

  • 深拷贝

    深拷贝在拷贝时会将引用类型的数据将引用地址所指向的对象也拷贝一份并返回地址,再将返回的地址重新赋值给引用类型的数据字段。

序列化机制实现深拷贝
@Override
    protected Product clone() throws CloneNotSupportedException {
        // 通过序列化的方式clone实例,由于涉及到io流,所以比较消耗性能
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
        } catch (IOException e) {
            e.printStackTrace();
        }

        ByteArrayInputStream bis = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        try {
            ObjectInputStream ois = new ObjectInputStream(bis);
            Product product = (Product) ois.readObject();
            return product;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

2、模式定义

指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

3、应用场景

当代码不应该依赖于需要复制的对象的具体类时,请使用Prototype模式

4、优点

  • 可以不耦合具体类的情况下克隆对象
  • 避免重复的初始化代码
  • 更方便的构建复杂的对象

5、在源码中的应用

Spring源码中的应用

java.util.Arrays:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    /**
     * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
     * elements themselves are not copied.)
     * @return a clone of this <tt>ArrayList</tt> instance
     */
	public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }
}



org.springframework.beans.factory.support.AbstractBeanDefinition:

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
      implements BeanDefinition, Cloneable {

    @Override
	public Object clone() {
		return cloneBeanDefinition();
	}
    
    protected AbstractBeanDefinition(BeanDefinition original) {
		setParentName(original.getParentName());
		setBeanClassName(original.getBeanClassName());
		setScope(original.getScope());
		setAbstract(original.isAbstract());
		setFactoryBeanName(original.getFactoryBeanName());
		// ...
	}

}

6、代码举例

public class PrototypeTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        BaseInfo baseInfo = new BaseInfo("xxx");
        Product product = new Product("part1", "part2", "part3", "part4", baseInfo);
        Product clone = product.clone();
        System.out.println("original: " + product);
        System.out.println("clone: " + clone);

        product.getBeasInfo().setCompanyName("yyy");
        System.out.println("original: " + product);
        System.out.println("clone: " + clone);
    }
}

class BaseInfo implements Cloneable, Serializable {
    static final long serialVersionUID = 42L;

    private String companyName;

    @Override
    protected BaseInfo clone() throws CloneNotSupportedException {
        return (BaseInfo)super.clone();
    }

     // set... get.... construct...  toString...
}

class Product implements Cloneable,Serializable{
    static final long serialVersionUID = 42L;

    private String part1;
    private String part2;
    private String part3;
    private String part4;
    private BaseInfo baseInfo;
    // ...
    
    @Override
    protected Product clone() throws CloneNotSupportedException {
        // 通过Object.clone方法clone实例
//        Product product = (Product) super.clone();
//        BaseInfo baseInfo = product.getBeasInfo().clone();
//        product.setBeasInfo(baseInfo);
//        return product;

        // 通过序列化的方式clone实例,由于涉及到io流,所以比较消耗性能
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream);
            oos.writeObject(this);
        } catch (IOException e) {
            e.printStackTrace();
        }

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        try {
            ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream);
            Product product = (Product) ois.readObject();
            return product;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
	
    // set... get.... construct...  toString...
}

五、享元模式

1、模式定义

运用共享技术有效的支持大量细粒度的对象

2、优点

如果系统有大量的类似对象,可以节省大量的内存及CPU资源

3、在源码中的应用

JDK中的应用
String, Integer, Long.....;
com.sun.org.apache.bcel.internal.generic.InstructionConst;

4、代码举例

public class FlyWeightTest {
    public static void main(String[] args) {
        TreeNode treeNode = new TreeNode(2, 3, TreeFactory.getTree("xxxx", "xxxxxxgggg"));
        System.out.println(treeNode);
        TreeNode treeNode1 = new TreeNode(33, 2, TreeFactory.getTree("xxxx", "xxxxxxss"));
        System.out.println(treeNode1);
        TreeNode treeNode2 = new TreeNode(5, 4, TreeFactory.getTree("xxxx", "xxxxxxffff"));
        System.out.println(treeNode2);
    }
}

class TreeFactory {
    private static Map<String, Tree> treeMap = new ConcurrentHashMap<>();

    public static Tree getTree(String treeName, String data) {
        if (treeMap.containsKey(treeName)) {
            Tree tree = treeMap.get(treeName);
            tree.setData(data);
            return tree;
        }
        Tree tree = new Tree(treeName, data);
        treeMap.put(treeName, tree);
        return tree;
    }
}

class TreeNode {
    private Integer x;
    private Integer y;
    private Tree tree;

	// set get toString construct  
}

class Tree {
    private String treeName;
    private String data;

    public Tree(String treeName, String data) {
        System.out.println(treeName + " tree is created, the data is " + data + ".");
        this.treeName = treeName;
        this.data = data;
    }
	
    // set get toString
    
}

六、门面模式

1、模式定义

为子系统中的一组接口提供一个一致的接口,Facade模式定义了一个高层接口,这个接口使得这个子系统更加容易使用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sXDYHS8y-1630034734765)(C:\Users\29829\AppData\Roaming\Typora\typora-user-images\image-20210825143140153.png)]

2、应用场景

  • 当您需要使用复杂子系统的有限但直接的接口时,请使用Facade模式
  • 当您想要将子系统组织成层时,请使用Facade模式

3、优点

简化客户端的调用

4、源码中的经典应用

org.apache.catelina.connector.RequestFacade;

5、代码举例

public class FacadeTest {
    public static void main(String[] args) {
        Client1 client1 = new Client1();
        client1.doSomething1();

        Client2 client2 = new Client2();
        client2.doSomething2();
    }
}

class Client1{
    private Facade facade = new Facade();

    public void doSomething1(){
        facade.doSomethingFacade();
    }
}

class Client2{
    private Facade facade = new Facade();

    public void doSomething2(){
        facade.doSomethingFacade();
    }
}

class Facade{
    private SubSystem1 subSystem1 = new SubSystem1();
    private SubSystem2 subSystem2 = new SubSystem2();
    private SubSystem3 subSystem3 = new SubSystem3();

    public void doSomethingFacade(){
        subSystem1.method1();
        subSystem2.method2();
        subSystem3.method3();
    }
}

class SubSystem1{
    public void method1(){
        System.out.println("SubSystem1 method1 is executed.");
    }
}

class SubSystem2{
    public void method2(){
        System.out.println("SubSystem2 method2 is executed.");
    }
}

class SubSystem3{
    public void method3(){
        System.out.println("SubSystem3 method3 is executed.");
    }
}

七、适配器模式Adapter

1、模式定义

将一个类的接口转换成客户端希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oyRW42bx-1630034734766)(C:\Users\29829\AppData\Roaming\Typora\typora-user-images\image-20210825144913905.png)]

2、应用场景

  • 当你希望使用某些现有类,但其接口与您的其他代码不兼容时,可以使用适配器模式。
  • 当希望重用几个现有的子类,这些子类缺少一些不能添加到超类中的公共功能时,可以使用适配器模式

3、优点

  • 符合单一职责原则
  • 符合开闭原则

4、JdK&Spring源码中的应用

JDK:
java.util.Arrays#asList();
java.util.Collections#list();

Spring:
org.springframwork.context.event.GenericApplicationListennerAdapter;

5、代码举例

对象适配器模式
/**
 * 对象适配器模式
 * @author Jamison
 * @version 1.0
 * @date 2021/8/25 14:52
 */
public class AdapterTest {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();

        Adapter adapter = new Adapter(adaptee);
        int i = adapter.output5v();
        System.out.println(i);
    }
}

class Adaptee{
    public int output220v(){
        return 220;
    }
}

interface Target{
    int output5v();
}

class Adapter implements Target{
    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public int output5v() {
        int i = adaptee.output220v();
        // ...
        System.out.println("原始电压:" + i + "v --->输出电压:" + 5);

        return 5;
    }
}
类适配器模式
/**
 * 类适配器模式,其缺点就是客户端可以看到适配器以内的内部方法
 * @author Jamison
 * @version 1.0
 * @date 2021/8/25 15:42
 */
public class AdapterTest2 {
    public static void main(String[] args) {

    }
}

class Adaptee{
    public int output220v(){
        return 220;
    }
}

interface Target{
    int output5v();
}

class Adapter extends Adaptee implements Target{
    @Override
    public int output5v() {
        int i = output220v();
        // ...
        System.out.println("原始电压:" + i + "v --->输出电压:" + 5);

        return 5;
    }
}

八、装饰者模式

1、模式定义

在不改变原有对象的基础上,将功能附加到对象上

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GsWK7yWb-1630034734767)(C:\Users\29829\AppData\Roaming\Typora\typora-user-images\image-20210825155647421.png)]

2、应用场景

扩展一个类的功能或给一个类添加附加职责

3、优点

  • 不改变原有对象的情况下给一个对象扩展功能
  • 使用不同的组合可以实现不同的效果
  • 符合开闭原则

4、在源码中的应用

Servlet Api:
javax.servlet.http.httpServiceRequestWrapper;
javax.servlet.http.httpServiceResponseWrapper;

5、代码举例

public class DacoratorTest {
    public static void main(String[] args) {
        Component component = new ConcreteDecorator2(new ConcreteDecorator1(new ConcreteComponent()));
        component.operation();
    }
}

interface Component{
    void operation();
}

class ConcreteComponent implements Component{

    @Override
    public void operation() {
        System.out.println("拍照.");
    }
}

abstract class Decorator implements Component{
    private Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        component.operation();
    }
}

class ConcreteDecorator1 extends Decorator{

    public ConcreteDecorator1(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        System.out.println("添加滤镜.");
        super.operation();
    }
}

class ConcreteDecorator2 extends Decorator{

    public ConcreteDecorator2(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        System.out.println("添加瘦脸.");
        super.operation();
    }
}

九、策略模式Strategy

1、模式定义

定义了算法族,分别封装起来,让它们之间可以互相替换,此模式的变化独立于算法的使用者。

在这里插入图片描述

2、案例

植物大战僵尸
在这里插入图片描述

3、代码举例

public class StrategyTest {
    public static void main(String[] args) {
        AbstractZombie zombie = new NormalZombie();
        zombie.dispaly();
        zombie.move();
        zombie.attack();

        zombie.setAttack(new HitAttack());
        zombie.attack();
    }
}

interface Moveable{
    void move();
}

interface Attack{
    void attack();
}

class StepByStepMove implements Moveable{

    @Override
    public void move() {
        System.out.println("一步一步的走.");
    }
}

class BiteAttack implements Attack{

    @Override
    public void attack() {
        System.out.println("咬.");
    }
}

class HitAttack implements Attack{

    @Override
    public void attack() {
        System.out.println("头撞.");
    }
}

abstract class AbstractZombie{
    private Moveable moveable;
    private Attack attack;

    public AbstractZombie(Moveable moveable, Attack attack) {
        this.moveable = moveable;
        this.attack = attack;
    }

    abstract void dispaly();
    void move(){
        moveable.move();
    }
    void attack(){
        attack.attack();
    }
    
    // set get
}

class NormalZombie extends AbstractZombie{
    public NormalZombie(){
        this(new StepByStepMove(), new BiteAttack());
    }

    public NormalZombie(Moveable moveable, Attack attack) {
        super(moveable, attack);
    }

    @Override
    void dispaly() {
        System.out.println("普通僵尸.");
    }
}

class FlagZombie extends AbstractZombie {
    public FlagZombie(){
        super(new StepByStepMove(), new BiteAttack());
    }

    public FlagZombie(Moveable moveable, Attack attack) {
        super(moveable, attack);
    }

    @Override
    void dispaly() {
        System.out.println("旗手僵尸.");
    }
}

4、在源码中的应用

java.lang.Comparable;
public interface Comparable<T> {
    // 让子类去实现
    public int compareTo(T o);
}

org.springframework.beans.factory.support.InstantiationStrategy;
public interface InstantiationStrategy {}

十、模板方法模式

1、模式定义

定义一个操作的算法骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定的步骤。

其实直白点理解就是,父类定义并调用模板,子类去实现这个模板方法。

2、代码举例

HttpServlet

public abstract class HttpServlet extends GenericServlet {
    
    // 在这里顶一个了一套骨架,get请求就走doGet方法,post请求就走doPost方法....。其中doGet、doPost等方法交由子类去实现,子类没有实现直接报错。
    
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = lStrings.getString("http.method_get_not_supported");
        this.sendMethodNotAllowed(req, resp, msg);
    }
    
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = lStrings.getString("http.method_post_not_supported");
        this.sendMethodNotAllowed(req, resp, msg);
    }
    
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader("If-Modified-Since");
                } catch (IllegalArgumentException var9) {
                    ifModifiedSince = -1L;
                }

                if (ifModifiedSince < lastModified / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }
    
}

AbstractController

public abstract class AbstractController extends WebContentGenerator implements Controller {
    
    // 骨架
    @Nullable
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (HttpMethod.OPTIONS.matches(request.getMethod())) {
            response.setHeader("Allow", this.getAllowHeader());
            return null;
        } else {
            this.checkRequest(request);
            this.prepareResponse(response);
            if (this.synchronizeOnSession) {
                HttpSession session = request.getSession(false);
                if (session != null) {
                    Object mutex = WebUtils.getSessionMutex(session);
                    synchronized(mutex) {
                        return this.handleRequestInternal(request, response);
                    }
                }
            }

            return this.handleRequestInternal(request, response);
        }
    }
    
    // 子类实现
    @Nullable
    protected abstract ModelAndView handleRequestInternal(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}

十一、观察者模式

1、模式定义

定义了对象之间的一对多依赖,让多个观察者对象同时监听某个主题对象,当主题对象发生变化时,它的所有依赖者都会收到通知并更新。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C12g5Y7p-1630034734770)(C:\Users\29829\AppData\Roaming\Typora\typora-user-images\image-20210825180448641.png)]

2、应用场景

当更改一个对象的状态可能需要更改其他对象时,并且实际的对象集事先未知或动态更改时,使用观察者模式。

3、优点

  • 符合开闭原则
  • 可以在运行时建立对象之间的关系

4、JDK&Spring源码中的应用

JDK:
java.util.Observable;

Spring:
org.sprignframework.context.ApplicationListenner;

5、代码举例

public class ObserverTest {
    public static void main(String[] args) {
        Subject subject = new Subject();
        Task1 observer = new Task1();
        subject.addObserver(observer);
        Task2 observer1 = new Task2();
        subject.addObserver(observer1);
        subject.notifyObserver("ssss");

        System.out.println("=====================");
        subject.removeObserver(observer);
        subject.notifyObserver("xxxx");
    }
}

// 主题
class Subject{
    private List<Observer> list = new ArrayList<>();

    public void addObserver(Observer observer){
        list.add(observer);
    }

    public void removeObserver(Observer observer){
        list.remove(observer);
    }

    public void notifyObserver(Object o){
        for (Observer observer : list) {
            observer.update(o);
        }
    }
}

// 观察者
interface Observer {
    void update(Object o);
}

class Task1 implements Observer{
    @Override
    public void update(Object o) {
        System.out.println("Task1 update executed. " + o);
    }
}

class Task2 implements Observer{

    @Override
    public void update(Object o) {
        System.out.println("Task2 executed. " + o);
    }
}

十二、责任链模式

1、模式定义

为请求创建了一个接受者对象的处理链。

2、应用场景

一个请求的处理需要多个对象当中的一个或多个协作处理。

3、优点

  • 请求的发送者和接受者解耦
  • 可以控制执行的频率
  • 符合开闭原则和单一职责原则

4、在源码中的应用

javax.servlet.Filter;
javax.servlet.FilterChain;

5、代码举例

public class ChainOfResponsibilityTest {
    public static void main(String[] args) {
        Request.RequestBuilder requestBuilder = new Request.RequestBuilder().frequentOk(true).loggedOn(false);
        Request request = requestBuilder.build();


        Handler handler = new RequestFraquentHandler(new RequestLoggingHandler(null));
        Boolean result = handler.handler(request);
        if (result){
            System.out.println("请求访问正常.");
        }else {
            System.out.println("访问异常.");
        }

    }
}

abstract class Handler{
    private Handler next;

    public Handler(Handler next) {
        this.next = next;
    }

    abstract Boolean handler(Request request);
	
    // get set
}

class RequestFraquentHandler extends Handler {

    public RequestFraquentHandler(Handler next) {
        super(next);
    }

    @Override
    Boolean handler(Request request) {
        System.out.println("访问频率控制.");
        Boolean frequentOk = request.getFrequentOk();
        if (frequentOk){
            Handler next = this.getNext();
            if (next == null){
                return true;
            }
            if (!next.handler(request)){
                return false;
            }else {
                return true;
            }
        }

        return false;
    }
}

class RequestLoggingHandler extends Handler{

    public RequestLoggingHandler(Handler next) {
        super(next);
    }

    @Override
    Boolean handler(Request request) {
        System.out.println("登录验证.");
        Boolean loggedOn = request.getLoggedOn();
        if (loggedOn){
            Handler next = this.getNext();
            if (next == null){
                return true;
            }
            if (!next.handler(request)){
                return false;
            }else {
                return true;
            }
        }

        return false;
    }
}

class Request{
    private Boolean loggedOn;
    private Boolean frequentOk;
    private Boolean isPermits;
    private Boolean containsSensitiveWord;
    private String responseBody;

    public Request(Boolean loggedOn, Boolean frequentOk, Boolean isPermits, Boolean containsSensitiveWord) {
        this.loggedOn = loggedOn;
        this.frequentOk = frequentOk;
        this.isPermits = isPermits;
        this.containsSensitiveWord = containsSensitiveWord;
    }

    static class RequestBuilder{
        private Boolean loggedOn;
        private Boolean frequentOk;
        private Boolean isPermits;
        private Boolean containsSensitiveWord;

        RequestBuilder loggedOn(Boolean loggedOn){
            this.loggedOn = loggedOn;
            return this;
        }

        RequestBuilder frequentOk(Boolean frequentOk){
            this.frequentOk = frequentOk;
            return this;
        }

        RequestBuilder isPermits(Boolean isPermits){
            this.isPermits = isPermits;
            return this;
        }

        RequestBuilder containsSensitiveWord(Boolean containsSensitiveWord){
            this.containsSensitiveWord = containsSensitiveWord;
            return this;
        }

        Request build(){
            return new Request(this.loggedOn, this.frequentOk, this.isPermits, this.containsSensitiveWord);
        }
    }

   // get set
}

后序补上。。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值