zoukankan      html  css  js  c++  java
  • spring-spring中的设计模式

    简单工厂模式

    介绍

    工厂类拥有一个工厂方法(create),接受了一个参数,通过不同的参数实例化不同的产品类。

    优缺点

    • 优点:
      • 很明显,简单工厂的特点就是“简单粗暴”,通过一个含参的工厂方法,我们可以实例化任何产品类,上至飞机火箭,下至土豆面条,无所不能。
      • 所以简单工厂有一个别名:上帝类。
    • 缺点:
      • 任何”东西“的子类都可以被生产,负担太重。当所要生产产品种类非常多时,工厂方法的代码量可能会很庞大。
      • 遵循开闭原则(对拓展开放,对修改关闭)的条件下,简单工厂对于增加新的产品,无能为力。因为增加新产品只能通过修改工厂方法来实现。

    工厂方法正好可以解决简单工厂的这两个缺点。

    示例

    • 普通-简单工厂类:
    public class AnimalFactory {
    
        //简单工厂设计模式(负担太重、不符合开闭原则)
        public static Animal createAnimal(String name){
            if ("cat".equals(name)) {
                return new Cat();
            }else if ("dog".equals(name)) {
                return new Dog();
            }else if ("cow".equals(name)) {
                return new Dog();
            }else{
                return null;
            }
        }
    }
    • 静态方法工厂
    /该简单工厂,也称为静态方法工厂
    public class AnimalFactory2 {
    
        public static Dog createDog(){
            return new Dog();
        }
        
        public static Cat createCat(){
            return new Cat();
        }
    }

    工厂方法模式

    介绍

    工厂方法是针对每一种产品提供一个工厂类。

    通过不同的工厂实例来创建不同的产品实例。

    优缺点

    • 优点:

      • 工厂方法模式就很好的减轻了工厂类的负担,把某一类/某一种东西交由一个工厂生产;(对应简单工厂的缺点1)
      • 同时增加某一类”东西“并不需要修改工厂类,只需要添加生产这类”东西“的工厂即可,使得工厂类符合开放-封闭原则。
    • 缺点:

      • 对于某些可以形成产品族的情况处理比较复杂。

    示例

    • 抽象出来的工厂对象
    // 抽象出来的动物工厂----它只负责生产一种产品
    public abstract class AnimalFactory {
        // 工厂方法
        public abstract Animal createAnimal();
    }
    • 具体的工厂对象
    // 具体的工厂实现类
    public class CatFactory extends AnimalFactory {
    
        @Override
        public Animal createAnimal() {
            return new Cat();
        }
    }

    抽象工厂模式

    介绍

    • 抽象工厂是应对产品族概念的。

      例如,汽车可以分为轿车、SUV、MPV等,也分为奔驰、宝马等。我们可以将奔驰的所有车看作是一个产品族,而将宝马的所有车看作是另一个产品族。分别对应两个工厂,一个是奔驰的工厂,另一个是宝马的工厂。与工厂方法不同,奔驰的工厂不只是生产具体的某一个产品,而是一族产品(奔驰轿车、奔驰SUV、奔驰MPV)。“抽象工厂”的“抽象”指的是就是这个意思。

    • 上边的工厂方法模式是一种极端情况的抽象工厂模式(即只生产一种产品的抽象工厂模式),而抽象工厂模式可以看成是工厂方法模式的一种推广。

    工厂模式区别

    • 简单工厂 : 用来生产同一等级结构中的任意产品。(不支持拓展增加产品)

    • 工厂方法 : 用来生产同一等级结构中的固定产品。(支持拓展增加产品) 

    • 抽象工厂 : 用来生产不同产品族的全部产品。(不支持拓展增加产品;支持增加产品族)

    单例模式

    介绍

    单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:

    1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。

    2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。

    示例

    • 饿汉式单例
    public class Student1 {
        // 2:成员变量初始化本身对象
        private static Student1 student = new Student1();
    
        // 1:构造私有
        private Student1() {
        }
    
        // 3:对外提供公共方法获取对象
        public static Student1 getSingletonInstance() {
            return student;
        }
    }
    • 懒汉式单例
    public class Student5 {
    
        private Student5() {
        }
        /*
         * 此处使用一个内部类来维护单例 JVM在类加载的时候,是互斥的,所以可以由此保证线程安全问题
         */
        private static class SingletonFactory {
            private static Student5 student = new Student5();
        }
        /* 获取实例 */
        public static Student5 getSingletonInstance() {
            return SingletonFactory.student;
        }
    }

    原型模式

    介绍

    原型模式虽然是创建型的模式,但是与工厂模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。

    示例

    • 先创建一个原型类:
    public class Prototype implements Cloneable {  
      
        public Object clone() throws CloneNotSupportedException {  
            Prototype proto = (Prototype) super.clone();  
            return proto;  
        }  
    } 

    很简单,一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB,因为此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法,而在Object类中,clone()是native的,具体怎么实现,此处不再深究。

    在这儿,我将结合对象的浅复制和深复制来说一下,首先需要了解对象深、浅复制的概念:

    • 浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的

    • 深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底

    • 写一个深浅复制的例子
    public class Prototype implements Cloneable, Serializable {  
      
        private static final long serialVersionUID = 1L;  
        private String string;  
      
        private SerializableObject obj;  
      
        /* 浅复制 */  
        public Object clone() throws CloneNotSupportedException {  
            Prototype proto = (Prototype) super.clone();  
            return proto;  
        }  
      
        /* 深复制 */  
        public Object deepClone() throws IOException, ClassNotFoundException {  
      
            /* 写入当前对象的二进制流 */  
            ByteArrayOutputStream bos = new ByteArrayOutputStream();  
            ObjectOutputStream oos = new ObjectOutputStream(bos);  
            oos.writeObject(this);  
      
            /* 读出二进制流产生的新对象 */  
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());  
            ObjectInputStream ois = new ObjectInputStream(bis);  
            return ois.readObject();  
        }  
      
        public String getString() {  
            return string;  
        }  
      
        public void setString(String string) {  
            this.string = string;  
        }  
      
        public SerializableObject getObj() {  
            return obj;  
        }  
      
        public void setObj(SerializableObject obj) {  
            this.obj = obj;  
        }  
      
    }  
      
    class SerializableObject implements Serializable {  
        private static final long serialVersionUID = 1L;  
    }  

    构建者模式

    介绍

    建造者模式的定义是:将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。

    建造者模式的角色定义,在建造者模式中存在以下4个角色:

    1. builder:为创建一个产品对象的各个部件指定抽象接口。
    2. ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。
    3. Director:构造一个使用Builder接口的对象。
    4. Product:表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。

    工厂模式和构建者模式的区别

    构建者模式和工厂模式很类似,区别在于构建者模式是一种个性化产品的创建。而工厂模式是一种标准化的产品创建。

    • 导演类:按照一定的顺序或者一定的需求去组装一个产品。

    • 构造者类:提供对产品的不同个性化定制,最终创建出产品。

    • 产品类:最终的产品

    示例

    • 构建者
    // 构建器
    public class StudentBuilder {
    
        // 需要构建的对象
        private Student student = new Student();
    
        public StudentBuilder id(int id) {
            student.setId(id);
            return this;
        }
    
        public StudentBuilder name(String name) {
            student.setName(name);
            return this;
        }
    
        public StudentBuilder age(int age) {
            student.setAge(age);
            return this;
        }
    
        public StudentBuilder father(String fatherName) {
            Father father = new Father();
            father.setName(fatherName);
            student.setFather(father);
            return this;
        }
    
        // 构建对象
        public Student build() {
            return student;
        }
    }
    • 导演类
    // 导演类/测试类
    public class BuildDemo {
    
        public static void main(String[] args) {
    
            StudentBuilder builder = new StudentBuilder();
            // 决定如何创建一个Student
            Student student = builder.age(1).name("zhangsan").father("zhaosi").build();
            System.out.println(student);
    
        }
    }

    适配器模式

    适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式

    核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口是Targetable,通过Adapter类,将Source的功能扩展到Targetable里,看代码:

    public class Source {   
         public void method1() {  
             System.out.println("this is original method!");  
         }  
     }  
    public interface Targetable {  
         /* 与原类中的方法相同 */  
         public void method1();  
         /* 新类的方法 */  
         public void method2();  
     }
    public class Adapter extends Source implements Targetable {  
         @Override  
         public void method2() {  
             System.out.println("this is the targetable method!");  
         }  
     }  

    Adapter类继承Source类,实现Targetable接口,下面是测试类:

     
    public class AdapterTest {  
         public static void main(String[] args) {  
             Targetable target = new Adapter();  
             target.method1();  
             target.method2();  
         }  
     }  

    这样Targetable接口的实现类就具有了Source类的功能。

    对象的适配器模式

    基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。

    public class Wrapper implements Targetable {  
        private Source source;  
        public Wrapper(Source source){  
            super();  
            this.source = source;  
        }  
        @Override  
         public void method2() {  
             System.out.println("this is the targetable method!");  
         }    
         @Override  
         public void method1() {  
             source.method1();  
         }  
     }

    接口的适配器模式

    第三种适配器模式是接口的适配器模式,接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。

    public interface Sourceable {      
         public void method1();  
         public void method2();  
     } 
    public abstract class Wrapper2 implements Sourceable{  
           
         public void method1(){}  
         public void method2(){}  
     }  
    public class SourceSub1 extends Wrapper2 {  
         public void method1(){  
             System.out.println("the sourceable interface's first Sub1!");  
         }  
     } 
    public class SourceSub2 extends Wrapper2 {  
         public void method2(){  
             System.out.println("the sourceable interface's second Sub2!");  
         }  
     } 

    讲了这么多,总结一下三种适配器模式的应用场景:

    • 类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。

    • 对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。

    • 接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。

    装饰模式

    顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下:

     public interface Sourceable {  
         public void method();  
     }
     public class Source implements Sourceable {   
         @Override  
         public void method() {  
             System.out.println("the original method!");  
         }  
     }  
    public class Decorator implements Sourceable {    
         private Sourceable source;         
         public Decorator(Sourceable source){  
             super();  
             this.source = source;  
         }  
         @Override  
         public void method() {  
             System.out.println("before decorator!");  
             source.method();  
             System.out.println("after decorator!");  
         }  
     } 

    装饰器模式的应用场景:

    1. 需要扩展一个类的功能。
    2. 动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)

    缺点:

    ​ 产生过多相似的对象,不易排错!

    代理模式

    其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作。代理又分为动态代理和静态代理

    静态代理

    比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法。

    public interface Sourceable {  
         public void method();  
     }
    public class Source implements Sourceable {    
         @Override  
         public void method() {  
             System.out.println("the original method!");  
         }  
     }
    public class Proxy implements Sourceable {    
         private Source source;  
         public Proxy(){  
             super();  
             this.source = new Source();  
         }  
         @Override  
         public void method() {  
             before();  
             source.method();  
             atfer();  
         }  
         private void atfer() {  
             System.out.println("after proxy!");  
         }  
         private void before() {  
             System.out.println("before proxy!");  
         }  
     }

    代理模式的应用场景:

    如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:

    1. 修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。
    2. 就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。

    使用代理模式,可以将功能划分的更加清晰,有助于后期维护!

    动态代理

    JDK动态代理
    public class JDKProxyFactory implements InvocationHandler {
    
        // 目标对象的引用
        private Object target;
    
        // 通过构造方法将目标对象注入到代理对象中
        public JDKProxyFactory(Object target) {
            super();
            this.target = target;
        }
    
        /**
         * @return
         */
        public Object getProxy() {
    
            // 如何生成一个代理类呢?
            // 1、编写源文件
            // 2、编译源文件为class文件
            // 3、将class文件加载到JVM中(ClassLoader)
            // 4、将class文件对应的对象进行实例化(反射)
    
            // Proxy是JDK中的API类
            // 第一个参数:目标对象的类加载器
            // 第二个参数:目标对象的接口
            // 第二个参数:代理对象的执行处理器
            Object object = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                    this);
    
            return object;
        }
    
        /**
         * 代理对象会执行的方法
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Method method2 = target.getClass().getMethod("saveUser", null);
            Method method3 = Class.forName("com.sun.proxy.$Proxy4").getMethod("saveUser", null);
            System.out.println("目标对象的方法:" + method2.toString());
            System.out.println("目标接口的方法:" + method.toString());
            System.out.println("代理对象的方法:" + method3.toString());
            System.out.println("这是jdk的代理方法");
            // 下面的代码,是反射中的API用法
            // 该行代码,实际调用的是[目标对象]的方法
            // 利用反射,调用[目标对象]的方法
            Object returnValue = method.invoke(target, args);
    
            return returnValue;
        }
    }
    CGLib动态代理
    public class CgLibProxyFactory implements MethodInterceptor {
    
        /**
         * @param clazz
         * @return
         */
        public Object getProxyByCgLib(Class clazz) {
            // 创建增强器
            Enhancer enhancer = new Enhancer();
            // 设置需要增强的类的类对象
            enhancer.setSuperclass(clazz);
            // 设置回调函数
            enhancer.setCallback(this);
            // 获取增强之后的代理对象
            return enhancer.create();
        }
    
        /***
         * Object proxy:这是代理对象,也就是[目标对象]的子类 
         * Method method:[目标对象]的方法 
         * Object[] arg:参数
         * MethodProxy methodProxy:代理对象的方法
         */
        @Override
        public Object intercept(Object proxy, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
            // 因为代理对象是目标对象的子类
            // 该行代码,实际调用的是父类目标对象的方法
            System.out.println("这是cglib的代理方法");
    
            // 通过调用子类[代理类]的invokeSuper方法,去实际调用[目标对象]的方法
            Object returnValue = methodProxy.invokeSuper(proxy, arg);
            // 代理对象调用代理对象的invokeSuper方法,而invokeSuper方法会去调用目标类的invoke方法完成目标对象的调用
            
            return returnValue;
        }
    }
  • 相关阅读:
    topcoder srm 681 div1
    topcoder srm 683 div1
    topcoder srm 684 div1
    topcoder srm 715 div1
    topcoder srm 685 div1
    topcoder srm 687 div1
    topcoder srm 688 div1
    topcoder srm 689 div1
    topcoder srm 686 div1
    topcoder srm 690 div1 -3
  • 原文地址:https://www.cnblogs.com/yintingting/p/10348534.html
Copyright © 2011-2022 走看看