Spring中用到的设计模式

一、工厂模式 BeanFactory
1、简单工厂模型,是指由一个工厂对象决定创建哪一种产品类的实例,工厂类负责创建的对象较少,客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心
优点:
只需传入一个正确的参数,就可以获取你所需要的对象,无须知道其创建的细节
缺点:
工厂类的职责相对过重,增加新的产品时需要修改工厂类的判断逻辑,违背开闭原则,不易于扩展过于复杂的产品结构

/**
 * @author : lssffy
 * @Description : 家庭
 * @date : 2023/12/18 23:36
 */
public interface IFamily {

    /** 吃饭 */
    public void eatingRice();
}


/**
 * @author : lssffy
 * @Description : joyous
 * @date : 2023/12/18 23:37
 */
public class JoyousFamily implements IFamily{
    public void eatingRice() {
        System.out.println("Joyous family eating rice");
    }
}


/**
 * @author : lssffy
 * @Description : tom
 * @date : 2023/12/18 23:40
 */
public class TomFamily implements IFamily{
    public void eatingRice() {
        System.out.println("tom family eating rice");
    }
}

/**
 * @author : lssffy
 * @Description : 测试类
 * @date : 2023/12/18 23:38
 */
public class IFamilyTest {

    public static void main(String[] args) {
        IFamily family = new JoyousFamily();
        family.eatingRice();
    }
}
2、工厂方法模式(Fatory Method Pattern)是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节,而且加入新的产品符合开闭原则
适用场景:
	创建对象需要大量重复的代码,客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。一个类通过其子类来指定创建哪个对象。
优点:
	用户只需关心所需产品对应的工厂,无须关心创建细节。
	加入新产品符合开闭原则,提高了系统的可扩展性
缺点:
	类的个数容易过多,增加了代码结构的复杂度。
	增加了系统的抽象性和理解难度。
/**
 * @author : lssffy
 * @Description : 工厂类
 * @date : 2023/12/18 23:41
 */
public class FamilyFactory {
    public IFamily create(Class<? extends IFamily> clazz) {
//        if("joyous".equals(name)){
//            return new JoyousFamily();
//        }else if("tom".equals(name)){
//            return new TomFamily();
//        }

//        try {
//            if (!(null == name || "".equals(name))) {
//                return (IFamily) Class.forName(name).newInstance();
//            }
//        }catch(Exception e){
//            e.printStackTrace();
//        }
        try{
            if(null !=clazz){
                return clazz.newInstance();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}
3、抽象工厂模式(Abastract Factory Pattern)是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。属于创建型设计模式
适用场景:
	客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。
	强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。
	提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
优点:
	具体产品在应用层代码隔离,无须关心创建细节
	将一个系列的产品族统一到一起创建
缺点:
	规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。
	增加了系统的抽象性和理解难度
/**
 * @author : lssffy
 * @Description : 抽象工厂
 * @date : 2023/12/19 17:16
 */
public interface FamilyFactory {
    Bridge createBridge();
    WatchTV createWatchTV();
}

/**
 * @author : lssffy
 * @Description : 冰箱
 * @date : 2023/12/19 17:14
 */
public interface Bridge {
    void open();
}


/**
 * @author : lssffy
 * @Description : 电视
 * @date : 2023/12/19 17:15
 */
public interface WatchTV {
    void watch();
}


/**
 * @author : lssffy
 * @Description : A品牌
 * @date : 2023/12/19 17:17
 */
public class JavaBridge implements Bridge{
    public void open() {
        System.out.println("JavaBridge");
    }
}

/**
 * @author : lssffy
 * @Description : A品牌
 * @date : 2023/12/19 17:18
 */
public class JavaWatchTV implements WatchTV{
    public void watch() {
        System.out.println("Java Watching");
    }
}


/**
 * @author : lssffy
 * @Description : A品牌工厂
 * @date : 2023/12/19 17:19
 */
public class JavaFamilyFactory implements FamilyFactory{
    public Bridge createBridge() {
        return new JavaBridge();
    }

    public WatchTV createWatchTV() {
        return new JavaWatchTV();
    }
}

/**
 * @author : lssffy
 * @Description : 测试类
 * @date : 2023/12/22 9:36
 */
public class Test {

    public static void main(String[] args) {
        FamilyFactory factory = new JavaFamilyFactory();
        factory.createWatchTV().watch();
        factory.createBridge().open();
    }
}

二、装饰器模式 BeanWrapper

三、代理模式 AopProxy
在生活中,我们经常见到这样的场景,如:租房中介、售票黄牛、婚介、经纪人、快递、事务代理、非侵入式日志监听等,这些都是代理模式的实际体现。代理模式(ProxyPattern)的定义也非常简单,是指为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客服端和目标对象之间起到中介作用,代理模式属于结构型设计模式。使用代理模式主要有两个目的:一保护目标对象,二增强目标对象。代理模式属于结构型模式,有静态代理和动态代理。
Java中的代理分为三种角色:
代理类(ProxySubject)
委托类(RealSubject)
接口(Subject)
在这里插入图片描述
Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期就生成,而动态代理代理类则是在Java运行时动态生成。
静态代理:
Java中的静态代理要求代理类(ProxySubject)和委托类(RealSubject)都实现同一个接口(Subject)。静态代理中代理类在编译期就已经确定,而动态代理则是JVM运行时动态生成,静态代理的效率相对动态代理来说相对高一些,但是静态代理代码冗余大,一单需要修改接口,代理类和委托类都需要修改。
动态代理:
Java中的动态代理依靠反射来实现,代理类和委托类不需要实现同一个接口。委托类需要实现接口,否则无法创建动态代理。代理类在JVM运行时动态生成,而不是编译期就能确定。Java动态代理主要涉及到两个类:java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler。代理类需要实现InvocationHandler接口或者创建匿名内部类,而Proxy用于创建动态动态。
Proxy用来动态创建一个代理对象的类,它提供了许多的方法,但是用的最多的就是newProxyInstance 这个方法。一般情况下,使用下面的newProxyInstance方法。

//返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

//loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
//interfaces: 一个Interface对象的数组,表示的是将要给需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样就能调用这组接口中的方法了
//h: 一个InvocationHandler对象,表示的是当这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

InvocationHandler每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。 在调用代理对象中的每一个方法时,在代码内部,都是直接调用了InvocationHandler的invoke方法,而invoke方法根据代理类传递给自己的method参数来区分是什么方法。

//在代理实例上处理方法调用并返回结果
Object invoke(Object proxy,Method method,Object[] args)
//proxy:指代所代理的那个真实对象
//method:指代的是所要调用真实对象的某个方法的Method对象
//args:指代的是调用真实对象某个方法时接受的参数
/**
 * @author : lssffy
 * @Description : 接口类
 * @date : 2023/12/21 14:02
 */
public interface HelloService {
    void sayHello();
}

/**
 * @author : lssffy
 * @Description : 实现
 * @date : 2023/12/21 14:03
 */
public class HelloServiceImpl implements HelloService {
    public void sayHello() {
        System.out.println("Hello");
    }
}
/**
 * @author : lssffy
 * @Description : 代理类
 * @date : 2023/12/21 14:05
 */
public class HelloServiceProxy {

    private HelloService helloService;

    public HelloServiceProxy(HelloService helloService) {
        this.helloService = helloService;
    }

    public Object getProxyInstance(){
        return Proxy.newProxyInstance(helloService.getClass().getClassLoader(), helloService.getClass().getInterfaces(), new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("before hello service");
                Object obj = method.invoke(helloService, args);
                System.out.println("after hello service");
                return obj;
            }
        });
    }
}
/**
 * @author : lssffy
 * @Description :
 * @date : 2023/12/21 10:21
 */
public class Test {
    public static void main(String[] args) {
        try{
            HelloService helloService = new HelloServiceImpl();
            HelloService dynamic = (HelloService) new HelloServiceProxy(helloService).getProxyInstance();
            dynamic.sayHello();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述
CGLIB动态代理类的机制,是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。” cglib 创建某个类A的动态代理类的模式 - 查找A上的所有非final的public类型的方法定义; - 将这些方法的定义转换成字节码; - 将组成的字节码转换成相应的代理的class对象; - 实现 MethodInterceptor接口,用来处理 对代理类上所有方法的请求(这个接口和JDK动态代理InvocationHandler的功能和角色是一样的)

/**
 * @author : lssffy
 * @Description : 代理类
 * @date : 2023/12/21 14:42
 */
public class CGlibClass {
    public void cglibProxy(){
        System.out.println("cglibProxy");
    }
}
/**
 * @author : lssffy
 * @Description : 代理实现类
 * @date : 2023/12/21 14:44
 */
public class CGLIBHandler implements MethodInterceptor{

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before execution");
        methodProxy.invokeSuper(o,objects);
        System.out.println("after execution");
        return null;
    }
}
/**
 * @author : lssffy
 * @Description :
 * @date : 2023/12/21 10:21
 */
public class Test {
    public static void main(String[] args) {
        CGLIBHandler cglibHandler = new CGLIBHandler();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CGlibClass.class);
        enhancer.setCallback(cglibHandler);
        CGlibClass proxy =(CGlibClass) enhancer.create();
        proxy.cglibProxy();
    }
}

在这里插入图片描述
JDK Proxy 生成对象的步骤如下:
1、拿到被代理对象的引用,并且获取到它的所有的接口,反射获取。
2、JDK Proxy 类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接口。
3、动态生成 Java 代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)。
4、编译新生成的 Java 代码.class。
5、再重新加载到 JVM 中运行

CGLib 和 JDK 动态代理对比
1.JDK 动态代理是实现了被代理对象的接口,CGLib 是继承了被代理对象。
2.JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib 使用 ASM框架写 Class 字节码,Cglib 代理实现更复杂,生成代理类比 JDK 效率低。
3.JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法,CGLib 执行效率更高。

静态代理实现较简单,代理类在编译期生成,效率高。缺点是会生成大量的代理类。
JDK动态代理不要求代理类和委托类实现同一个接口,但是委托类需要实现接口,代理类需要实现InvocationHandler接口。
动态代理要求代理类InvocationHandler接口,通过反射代理方法,比较消耗系统性能,但可以减少代理类的数量,使用更灵活。

1、静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步
新增,违背开闭原则。
2、动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开
闭原则。
3、若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成,
无需修改代理类的代码。

优点:
1、代理模式能将代理对象与真实被调用的目标对象分离。
2、一定程度上降低了系统的耦合度,扩展性好。
3、可以起到保护目标对象的作用。
4、可以对目标对象的功能增强
缺点:
1、代理模式会造成系统设计中类的数量增加。
2、在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。
3、增加了系统的复杂度

四、单例模式 ApplicationContext
单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。单例模式是创建型模式。单例模式在现实生活中应用也非常广泛。例如,国家主席、公司 CEO、部门经理等。在 J2EE 标准中,ServletContext、ServletContextConfig 等;在 Spring 框架应用中 ApplicationContext;数据库的连接池也都是单例形式。
饿汉式单例是在类加载的时候就立即初始化,并且创建单例对象。绝对线程安全,在线程还没出现以前就是实例化了,不可能存在访问安全问题。
优点:
没有加任何的锁、执行效率比较高,在用户体验上来说,比懒汉式更好。
缺点:
类加载的时候就初始化,不管用与不用都占着空间,浪费了内存,有可能占着茅坑不拉屎

/**
 * @author : lssffy
 * @Description : 饿汉式单例类
 * @date : 2023/12/22 9:55
 */
public class HungrySingleton {

    private HungrySingleton(){}

//    private static final HungrySingleton httpSingleton = new HungrySingleton();
    
    //静态代码块的方式
    private static final HungrySingleton httpSingleton;
    static {
        httpSingleton = new HungrySingleton();
    }

    public static HungrySingleton getInstance(){
        return httpSingleton;
    }
}
懒汉式单例是被外部类调用的时候内部类才会加载
/**
 * @author : lssffy
 * @Description : 懒汉式单例类
 * @date : 2023/12/22 10:06
 */
public class LazySimpleSingleton {

    private LazySimpleSingleton(){}

    private static LazySimpleSingleton lazy = null;

    public static LazySimpleSingleton getInstance(){
        if(lazy == null){
            synchronized (LazySimpleSingleton.class){
                if(lazy == null) {
                    lazy = new LazySimpleSingleton();
                }
            }
        }
        return lazy;
    }
}
/**
 * @author : lssffy
 * @Description : 静态内部类单例
 * @date : 2023/12/22 10:11
 */
//这种形式兼顾饿汉式的内存浪费,也兼顾 synchronized 性能问题
//完美地屏蔽了这两个缺
public class LazyInnerClassSingleton {

    //默认使用 LazyInnerClassGeneral 的时候,会先初始化内部类
    //如果没使用的话,内部类是不加载的
    private LazyInnerClassSingleton() {
    	//针对反射破坏单例,增加判断条件用于控制
        if(LazyHandler.lazy!=null){
            throw new RuntimeException("不允许创建多个实例");
        }
    }
    //每一个关键字都不是多余的
    //static 是为了使单例的空间共享
    //保证这个方法不会被重写,重载
    public static final LazyInnerClassSingleton getInstance(){
        return LazyHandler.lazy;
    }
    //默认不加载
    public static class LazyHandler{
        private static final LazyInnerClassSingleton lazy = new LazyInnerClassSingleton();
    }
}

序列化破坏单例

/**
 * @author : lssffy
 * @Description : 序列化破坏单例
 * @date : 2023/12/22 10:19
 */
public class SerializableSingleton implements Serializable {

    //序列化就是说把内存中的状态通过转换成字节码的形式
    //从而转换一个 IO 流,写入到其他地方(可以是磁盘、网络 IO)
    //内存中状态给永久保存下来了
    //反序列化
    //讲已经持久化的字节码内容,转换为 IO 流
    //通过 IO 流的读取,进而将读取的内容转换为 Java 对象
    //在转换过程中会重新创建对象 new
    private static final SerializableSingleton INSTANCE = new SerializableSingleton();

    private SerializableSingleton(){}

    public static SerializableSingleton getInstance(){
        return INSTANCE;
    }
    //加上这个方法可以防止序列化破坏单例
	private Object readResolve(){
        return INSTANCE;
    }
}

/**
 * @author : lssffy
 * @Description :测试类
 * @date : 2023/12/22 10:22
 */
public class SerializableSingletonTest {
    public static void main(String[] args) {
        SerializableSingleton s1 = null;
        SerializableSingleton s2 = SerializableSingleton.getInstance();
        FileOutputStream fos = null;
        try{
            fos = new FileOutputStream("SerializableSingleton.obj");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(s2);
            oos.flush();
            oos.close();

            FileInputStream fis = new FileInputStream("SerializableSingleton.obj");
            ObjectInputStream ois = new ObjectInputStream(fis);
            s1 = (SerializableSingleton) ois.readObject();
            ois.close();

            System.out.println(s1);
            System.out.println(s2);
            System.out.println(s1==s2);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

注册式单例为登记式单例,就是将每一个实例都登记到某一个地方,使用唯一的标识获取实例。注册式单例有两种写法:一种为容器缓存,一种为枚举登记。
/**
 * @author : lssffy
 * @Description : 注册式单例
 * @date : 2023/12/22 10:37
 */
public enum EnumSingleton {

    INSTANCE;

    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
    public static EnumSingleton getInstance(){
        return INSTANCE;
    }
}
/**
 * @author : lssffy
 * @Description : 测试类
 * @date : 2023/12/22 10:39
 */
public class EnumSingletonTest {
    public static void main(String[] args) {
        try {
            EnumSingleton enumSingleton1 = null;
            EnumSingleton enumSingleton2 = EnumSingleton.getInstance();
            enumSingleton2.setData(new Object());
            FileOutputStream fos = new FileOutputStream("EnumSingleton.obj");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(enumSingleton2);
            oos.flush();
            oos.close();

            FileInputStream fis = new FileInputStream("EnumSingleton.obj");
            ObjectInputStream ois = new ObjectInputStream(fis);
            enumSingleton1 = (EnumSingleton) ois.readObject();
            ois.close();
            System.out.println(enumSingleton1.getData());
            System.out.println(enumSingleton2.getData());
            System.out.println(enumSingleton1.getData()==enumSingleton2.getData());
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述
容器式单例

/**
 * @author : lssffy
 * @Description : 容器式单例
 * @date : 2023/12/22 10:46
 */
public class ContainerSingleton {
    private ContainerSingleton(){}

    private static Map<String,Object> ioc = new ConcurrentHashMap<String,Object>();

    public static Object getBean(String className){
        synchronized (ioc){
            if(!ioc.containsKey(className)){
                Object obj = null;
                try{
                    obj = Class.forName(className).newInstance();
                    ioc.put(className, obj);
                }catch(Exception e){
                    e.printStackTrace();
                }
                return obj;
            }else{
                return ioc.get(className);
            }
        }
    }
}

/**
 * @author : lssffy
 * @Description : 测试类
 * @date : 2023/12/22 10:50
 */
public class ContainerSingletonTest {
    public static void main(String[] args) {
        Object obj1 = ContainerSingleton.getBean("com.gupaoedu.vip.pattern.singleton.ContainerSingleton") ;
        Object obj2 = ContainerSingleton.getBean("com.gupaoedu.vip.pattern.singleton.ContainerSingleton") ;
        System.out.println(obj1);
        System.out.println(obj2);
        System.out.println(obj1==obj2);
    }
}

在这里插入图片描述

原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
使用场景:
	类初始化消耗资源较多
	new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
	构造函数比较复杂
	循环体中生产大量对象时
浅拷贝:如果原型对象的成员变量是值类型,将复制一份给克隆对象,也就是说在堆中拥有独立的空间;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。换句话说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。
/**
 * @author : lssffy
 * @Description :
 * @date : 2023/12/20 21:53
 */
public class Car {
    public int id;
    public String name;
}
/**
 * @author : lssffy
 * @Description :
 * @date : 2023/12/20 21:53
 */
public class Bus extends Car implements Cloneable, Serializable {
    public Oil oil;

    public Bus(){
        this.id = 11;
        this.name = "xiaoqiche";
        this.oil = new Oil();
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
/**
 * @author : lssffy
 * @Description :
 * @date : 2023/12/20 21:54
 */
public class Oil implements Serializable {
    public int right;
    public int left;

    public void big(){
        this.left = 2;
        this.right = 2;
    }

    public void small(){
        this.left /= 2;
        this.right /= 2;
    }
}
深拷贝:一种完全拷贝,无论是值类型还是引用类型都会完完全全的拷贝一份,在内存中生成一个新的对象,深拷贝有两种方式,一种是跟浅拷贝一样实现 Cloneable 接口,另一种是实现 Serializable 接口,用序列化的方式来实现深拷贝
/**
 * @author : lssffy
 * @Description :
 * @date : 2023/12/20 23:11
 */
@Data
public class Monkey implements Serializable {
    private int height;
    private int width;

}
/**
 * @author : lssffy
 * @Description :
 * @date : 2023/12/20 23:12
 */
@Data
public class Qtds implements Serializable {

    private int height;
    private int width;
    private Monkey monkey;

    public Object deepClone() throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);

        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        Qtds qtds = (Qtds) ois.readObject();
        return qtds;
    }
}

五、委派模式 DispatcherServlet
委派模式(Delegate Pattern)的基本作用是负责任务的调用和分配任务,跟代理模式很像,可以看做是一种特殊情况下的静态代理的全权代理,但是代理模式注重过程,而委派模式注重结果。委派模式在 Spring 中应用非常多,大家常用的 DispatcherServlet 其实就是用到了委派模式。现实生活中也常有委派的场景发生,

/**
 * @author : lssffy
 * @Description : 员工接口
 * @date : 2023/12/22 11:07
 */
public interface IEmployee {
    public void doing(String command);
}
/**
 * @author : lssffy
 * @Description : 员工A
 * @date : 2023/12/22 11:09
 */
public class EmployeeA implements IEmployee{
    public void doing(String command) {
        System.out.println("I am employeeA,I can ready working with the" + command);
    }
}
/**
 * @author : lssffy
 * @Description : 员工B
 * @date : 2023/12/22 11:10
 */
public class EmployeeB implements IEmployee{
    public void doing(String command) {
        System.out.println("I am employeeB,I can ready working with the" + command);
    }
}
/**
 * @author : lssffy
 * @Description : 项目经理
 * @date : 2023/12/22 11:26
 */
public class Leader implements IEmployee{

    private Map<String,IEmployee> target = new HashMap<String,IEmployee>();

    public Leader(){
        target.put("加密",new EmployeeA());
        target.put("登录",new EmployeeB());
    }

    public void doing(String command) {
        target.get(command).doing(command);
    }
}
/**
 * @author : lssffy
 * @Description : boss
 * @date : 2023/12/22 11:29
 */
public class Boss {

    public void common(String common,Leader leader){
        leader.doing(common);
    }
}
/**
 * @author : lssffy
 * @Description :
 * @date : 2023/12/22 11:30
 */
public class DelegateTest {
    public static void main(String[] args) {
    	//客户请求(Boss)、委派者(Leader)、被被委派者(Target)
		//委派者要持有被委派者的引用
		//代理模式注重的是过程, 委派模式注重的是结果
		//策略模式注重是可扩展(外部扩展),委派模式注重内部的灵活和复用
		//委派的核心:就是分发、调度、派遣
		//委派模式:就是静态代理和策略模式一种特殊的组合
        new Boss().common("登录",new Leader());
        new Boss().common("加密",new Leader());
    }
}

在这里插入图片描述
SpringMVC的DispatcherServlet实现委派模式

/**
 * @author : lssffy
 * @Description : 业务类
 * @date : 2023/12/22 13:50
 */
public class MemberController {
    public void getMemberById(String mid){

    }
}
/**
 * @author : lssffy
 * @Description : 业务类
 * @date : 2023/12/22 13:51
 */
public class OrderController {
    public void getOrderById(String mid){

    }
}
/**
 * @author : lssffy
 * @Description : 业务类
 * @date : 2023/12/22 13:52
 */
public class SystemController {
    public void logout(){

    }
}
/**
 * @author : lssffy
 * @Description : 委派类
 * @date : 2023/12/22 13:52
 */
public class DispatcherServlet extends HttpServlet {

    private void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception{
        String url = request.getRequestURI();
        String mid = request.getParameter("mid");
        if("getMemberById".equals(url)){
            new MemberController().getMemberById(mid);
        }else if(("getOrderById").equals(url)){
            new OrderController().getOrderById(mid);
        }else if("logout".equals(url)){
            new SystemController().logout();
        }else{
            response.getWriter().write("404 Not Found");
        }
    }

    protected void service(HttpServletRequest request, HttpServletResponse response) {
        try{
            doDispatch(request, response);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
<?xml version="1.0" encoding="UTF-8" ?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">

    <display-name>Web Application</display-name>

    <servlet>
        <servlet-name>delegateServlet</servlet-name>
        <servlet-class>com.gupaoedu.vip.pattern.delegate.mvc.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>delegateServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

六、策略模式 HandlerMapping
策略模式(Strategy Pattern)是指定义了算法家族、分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。
策略模式的应用场景
1、假如系统中有很多类,而他们的区别仅仅在于他们的行为不同。
2、一个系统需要动态地在几种算法中选择一种
实现案例

/**
 * @author : lssffy
 * @Description : 抽象类
 * @date : 2023/12/22 15:44
 */
public interface PromotionStrategy {
    void doPromotion();
}
/**
 * @author : lssffy
 * @Description : 策略类
 * @date : 2023/12/22 15:44
 */
public class CouponStrategy implements PromotionStrategy{
    public void doPromotion() {
        System.out.println("优惠券,直接抵扣");
    }
}
/**
 * @author : lssffy
 * @Description : 策略类
 * @date : 2023/12/22 15:46
 */
public class CashbackStrategy implements PromotionStrategy{
    public void doPromotion() {
        System.out.println("返现促销");
    }
}
/**
 * @author : lssffy
 * @Description : 策略类
 * @date : 2023/12/22 15:47
 */
public class GroupBuyStrategy implements PromotionStrategy{
    public void doPromotion() {
        System.out.println("拼团,享受团价");
    }
}
/**
 * @author : lssffy
 * @Description : 策略类
 * @date : 2023/12/22 15:48
 */
public class EmptyStrategy implements PromotionStrategy{
    public void doPromotion() {
        System.out.println("无优惠");
    }
}
/**
 * @author : lssffy
 * @Description : 活动
 * @date : 2023/12/22 15:49
 */
public class PromotionActivity {
    private PromotionStrategy promotionStrategy;

    public PromotionActivity(PromotionStrategy promotionStrategy){
        this.promotionStrategy = promotionStrategy;
    }

    public void execute(){
        promotionStrategy.doPromotion();
    }
}
/**
 * @author : lssffy
 * @Description : 测试类
 * @date : 2023/12/22 15:50
 */
public class PromotionTest {
    public static void main(String[] args) {
        PromotionActivity p1 = new PromotionActivity(new CouponStrategy());
        PromotionActivity p2 = new PromotionActivity(new CashbackStrategy());
        p1.execute();
        p2.execute();
    }
}

在这里插入图片描述
如果把上面这段测试代码放到实际的业务场景其实并不实用。
因为我们做活动时候往往是要根据不同的需求对促销策略进行动态选择的,并不会一次
性执行多种优惠。所以,我们的代码通常会这样写

/**
 * @author : lssffy
 * @Description : 测试类
 * @date : 2023/12/22 15:50
 */
public class PromotionTest {
    public static void main(String[] args) {
        PromotionActivity promotionActivity = null;
        String promotion = "COUPON";
        if(promotion.equals("COUPON")){
            promotionActivity = new PromotionActivity(new CouponStrategy());
        }else if(promotion.equals("CASHBACK")){
            promotionActivity = new PromotionActivity(new CashbackStrategy());
        }//......
        promotionActivity.execute();
    }
}

这样改造之后,满足了业务需求,客户可根据自己的需求选择不同的优惠策略了。但是,经过一段时间的业务积累,我们的促销活动会越来越多,我们是不需要思考代码是不是应该重构了,我们可以结合单例模式和工厂模式

/**
 * @author : lssffy
 * @Description : 工厂类
 * @date : 2023/12/22 15:59
 */
public class PromotionStrategyFactory {

    private static final Map<String,PromotionStrategy> PROMOTION_STRATEGY_MAP = new ConcurrentHashMap<String, PromotionStrategy>();
    static {
        PROMOTION_STRATEGY_MAP.put(PromotionKey.COUPON,new CouponStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.CASHBACK,new CashbackStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.GROUPBUY,new GroupBuyStrategy());
    }

    private static final PromotionStrategy DEFAULT_ACTIVITY = new EmptyStrategy();

    private PromotionStrategyFactory(){}

    public static PromotionStrategy getPromotionStrategy(String promotionKey){
        PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey);
        return promotionStrategy == null?DEFAULT_ACTIVITY:promotionStrategy;
    }

    private interface PromotionKey{
        String COUPON = "COUPON";
        String CASHBACK = "CASHBACK";
        String GROUPBUY = "GROUPBUY";
    }
}
/**
 * @author : lssffy
 * @Description : 测试类
 * @date : 2023/12/22 15:50
 */
public class PromotionTest {
    public static void main(String[] args) {
        String promotionKey = "COUPON";
        PromotionActivity promotionActivity = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey));
        promotionActivity.execute();
    }
}

在这里插入图片描述
支付类案例

/**
 * @author : lssffy
 * @Description : 抽象类
 * @date : 2023/12/22 16:29
 */
public abstract class Payment {
    //支付类型
    public abstract String getName();
    //查询余额
    protected abstract double queryBalance(String uid);
    //扣款支付
    public PayState pay(String uid,double amount){
        if(queryBalance(uid) < amount){
            return new PayState(500,"支付失败","余额不足");
        }
        return new PayState(200,"支付成功","支付金额:" + amount);
    }
}
/**
 * @author : lssffy
 * @Description : 支付宝
 * @date : 2023/12/22 16:51
 */
public class AliPay extends Payment{
    public String getName() {
        return "支付宝";
    }

    protected double queryBalance(String uid) {
        return 900;
    }
}
/**
 * @author : lssffy
 * @Description : 京东
 * @date : 2023/12/22 16:52
 */
public class JDPay extends Payment{
    public String getName() {
        return "京东白条";
    }

    protected double queryBalance(String uid) {
        return 500;
    }
}
/**
 * @author : lssffy
 * @Description : 微信支付
 * @date : 2023/12/22 16:53
 */
public class WechatPay extends Payment{
    public String getName() {
        return "微信自己付";
    }

    protected double queryBalance(String uid) {
        return 256;
    }
}
/**
 * @author : lssffy
 * @Description : 银联支付
 * @date : 2023/12/22 16:53
 */
public class UnionPay extends Payment{
    public String getName() {
        return "银联支付";
    }

    protected double queryBalance(String uid) {
        return 120;
    }
}
/**
 * @author : lssffy
 * @Description : 支付策略类
 * @date : 2023/12/22 16:54
 */
public class PayStrategy {
    public static final String ALI_PAY = "AliPay";
    public static final String JD_PAY = "JDPay";
    public static final String WECHAT_PAY = "WechatPay";
    public static final String UNION_PAY = "UnionPay";
    public static final String DEFAULT_PAY = ALI_PAY;

    private static final Map<String,Payment> payStrategy = new ConcurrentHashMap<String,Payment>();
    static {
        payStrategy.put(ALI_PAY,new AliPay());
        payStrategy.put(JD_PAY,new JDPay());
        payStrategy.put(WECHAT_PAY,new WechatPay());
        payStrategy.put(UNION_PAY,new UnionPay());
    }

    public static Payment get(String payKey){
        if(!payStrategy.containsKey(payKey)){
            return payStrategy.get(DEFAULT_PAY);
        }
        return payStrategy.get(payKey);
    }
}
/**
 * @author : lssffy
 * @Description : 支付状态类
 * @date : 2023/12/22 16:30
 */
public class PayState {
    private int code;
    private Object data;
    private String msg;

    PayState(int code, Object data, String msg){
        this.code = code;
        this.data = data;
        this.msg = msg;
    }

    @Override
    public String toString() {
        return ("支付状态:[" + code+ "];" + msg + ", 交易详情:" + data);
    }
}
/**
 * @author : lssffy
 * @Description : 订单类
 * @date : 2023/12/22 17:00
 */
public class Order {
    private String uid;
    private String orderId;
    private double price;

    Order(String uid, String orderId, double price){
        this.uid = uid;
        this.orderId = orderId;
        this.price = price;
    }

    public PayState pay(){
        return pay(PayStrategy.DEFAULT_PAY);
    }

    public PayState pay(String payKey){
        Payment payment = PayStrategy.get(payKey);
        System.out.println("欢迎使用" + payment.getName());
        System.out.println("本次交易金额为:" + price + ",开始扣款....");
        return payment.pay(uid,price);
    }
}
/**
 * @author : lssffy
 * @Description : 测试类
 * @date : 2023/12/22 17:04
 */
public class PayTest {
    public static void main(String[] args) {
        Order order  = new Order("1","2011111111",500);
        System.out.println(order.pay(PayStrategy.ALI_PAY));
    }
}

在这里插入图片描述

优点:
1、策略模式符合开闭原则。
2、避免使用多重条件转移语句,如 if…else…语句、switch 语句
3、使用策略模式可以提高算法的保密性和安全性
缺点:
1、客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
2、代码中会产生非常多策略类,增加维护难度

七、适配器模式 HandlerApdapter

八、模板方法模式 JdbcTemplate

九、观察者模式 ContextLoaderListener

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/265502.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第四部分 一阶逻辑基本概念

目录 主要内容 一阶逻辑命题符号化 一阶逻辑公式及其解释 个体词——所研究对象中可以独立存在的具体或抽象的客体 谓词——表示个体词性质或相互之间关系的词 量词——表示数量的词 例1 用0元谓词将命题符号化 例2 在一阶逻辑中将下面命题符号化 例如 例如 例3 给定解释 I 如下…

京东JDAPI:电商行业的得力助手

一、引言 在当今电商行业中&#xff0c;数据的获取与利用显得尤为重要。作为中国领先的电商平台&#xff0c;京东提供了丰富的API接口&#xff0c;其中JD商品详情API是关键之一&#xff0c;它允许第三方开发者获取京东平台上的商品详情信息。本文将深入探讨京东JD商品详情API在…

欧洲版OpenAI疑似将在24年发布并开源GPT-4级别模型!

大家好&#xff0c;我是二狗。 今天在推特上看到一条振奋人心的消息&#xff1a; “ 欧洲版OpenAI、法国初创公司 Mistral 首席执行官 Arthur Mensch 在法国国家广播电台宣布&#xff0c;Mistral 将在 2024 年发布开源 GPT-4 级别模型。” 这位老哥接着表示甚至可能是免费的&a…

前端传输formDate格式的数据,后端不能用@RequestBody接收

写了个接口&#xff0c;跟前端对接&#xff0c;前端说怎么一直415的报错 我寻思不对啊&#xff0c;我swagger都请求成功了&#xff0c;后来发现前端一直是以formdata格式提交的数据&#xff0c;这样我其实是可以不加RequestBody的&#xff1b; 知识点&#xff1a; RequestBody…

TrustZone之与非安全虚拟化交互

到目前为止&#xff0c;我们在示例中忽略了非安全状态中可能存在的虚拟化程序。当存在虚拟化程序时&#xff0c;虚拟机与安全状态之间的许多通信将通过虚拟化程序进行。 例如&#xff0c;在虚拟化环境中&#xff0c;SMC用于访问固件功能和可信服务。固件功能包括诸如电源管理之…

将遗留系统分解为微服务:第 2 部分

在当今不断发展的技术环境中&#xff0c;从整体架构向微服务的转变对于许多企业来说都是一项战略举措。这在报销计算系统领域尤其重要。正如我在上一篇文章第 1 部分应用 Strangler 模式将遗留系统分解为微服务-CSDN博客中提到的&#xff0c;让我们探讨如何有效管理这种转变。 …

前端学习——指令

vue作为前端框架&#xff0c;为了简化或实现一些特定功能&#xff0c;提供了很多指令&#xff0c;那什么是指令呢&#xff1f; 所谓的指令就是能够完成特定功能的一些vue语法&#xff0c;比如属性绑定指令v-bind&#xff0c;事件绑定指令v-on&#xff0c;循环指令v-for等。在v…

【Amazon 实验②】使用Amazon WAF做基础 Web Service 防护之自定义规则

文章目录 1. 自定义规则1.1 介绍 2. 实验步骤2.1 测试2.2 输出 上一篇章介绍了使用Amazon WAF做基础 Web Service 防护中的Web ACLs 配置 & AWS 托管规则的介绍和演示操作 【Amazon 实验①】使用Amazon WAF做基础 Web Service 防护&#xff0c;本篇章将继续介绍关于自定义…

2009-2022年31省细分产品出口数据/按hs码分的22类细分产品的出口数据

2009-2022年31省细分产品出口数据/按hs码分的22类细分产品的出口数据 1、时间&#xff1a;2009-2022年 2、指标&#xff1a;时间、流向名称、商品编码、商品名称、伙伴名称、主题编码、方式名称、金额&#xff08;美元&#xff09; 3、来源&#xff1a;海关贸易统计数据/海关…

智能优化算法应用:基于骑手优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于骑手优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于骑手优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.骑手优化算法4.实验参数设定5.算法结果6.…

[SQL]实验 视图和索引的应用

实验目的&#xff1a; [实验目的和要求] 1、掌握视图的创建、修改和重命名的方法 2、掌握视图中数据的操作 3、了解索引的作用 4、掌握索引的创建方法 实验步骤&#xff1a; 1、在销售管理数据库中&#xff0c;创建一个女职工视图&#xff0c;包括员工的编号、姓名、性别、雇佣…

多标签分类中常用指标和可视化例子

多标签分类中常用指标 1. 准确率&#xff08;Accuracy&#xff09; 准确率计算的是正确预测的标签比例。对于多标签分类&#xff0c;这通常是一个较为严格的指标&#xff0c;因为要求每个实例的所有标签都预测正确。 Accuracy 正确预测的标签数 总标签数 \text{Accuracy} \…

Qt前端技术:5.QSS

这个是表示QFrame中的pushButton中的子类和它子类的子类都将背景变为red 写成大于的时候表示只有直接的子类对象才会变 这个图中的QGroupBox和QPushButton都是QFrame的直接的子类 这个中的QGroupBox是QFrame的直接的子类但是QPushButton 是QGroupBox的子类&#xff0c;QPushB…

3. 结构型模式 - 组合模式

亦称&#xff1a; 对象树、Object Tree、Composite 意图 组合模式是一种结构型设计模式&#xff0c; 你可以使用它将对象组合成树状结构&#xff0c; 并且能像使用独立对象一样使用它们 问题 如果应用的核心模型能用树状结构表示&#xff0c; 在应用中使用组合模式才有价值。 …

基于JavaWeb的个人健康信息管理系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本个人健康信息管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据…

laravel 对接支付,本地穿透问题

本地穿透有好多工具&#xff0c;参考链接&#xff1a;https://zhuanlan.zhihu.com/p/339923535 我这边是用的 NATAPP 官网&#xff1a;https://natapp.cn/ 客户端下载&#xff1a;https://natapp.cn/# NATAPP1分钟快速新手图文教程&#xff1a;https://natapp.cn/article/n…

打造完美有声书体验,Audiobook Builder for Mac助您一键生成

在快节奏的生活中&#xff0c;有声书成为越来越多人追求放松与娱乐的方式。然而&#xff0c;找到合适的有声书却不容易&#xff0c;而Audiobook Builder for Mac正是为解决这个问题而诞生的完美解决方案。 Audiobook Builder for Mac是一款专业的有声书生成工具&#xff0c;它…

基于多反应堆的高并发服务器【C/C++/Reactor】(中)ChannelMap 模块的实现

&#xff08;三&#xff09;ChannelMap 模块的实现 这个模块其实就是为Channel来服务的&#xff0c;前面讲了Channel这个结构体里边它封装了文件描述符。假如说我们得到了某一个文件描述符&#xff0c;需要基于这个文件描述符进行它对应的事件处理&#xff0c;那怎么办呢&…

【分布式技术专题】「授权认证体系」深度解析OAuth2.0协议的原理和流程框架实现指南(授权流程和模式)

深度解析OAuth2.0协议的原理和流程框架实现指南 背景介绍OAuth1.0协议访问令牌案例分析 OAuth2.0OAuth2.0与OAuth1.0 OAuth2.0协议体系的Roles角色OAuth定义了四个角色资源所有者资源服务器客户端授权服务器 传统的客户机-服务器身份验证模型的问题协议流程 认证授权类型授权码…

Spring中你应该要知道的initMethod

文章目录 功能源码 功能 之前的文章中由解析过PostConstruct/PreDestroy&#xff0c;他们也是initMethod的一种形式&#xff0c;注解方式是后来才加入的&#xff0c;在源码中他们的命名都是一样的名字&#xff0c;都叫initMethod&#xff0c;不过他们却是有着很大的差别&#…