java设计模式之代理模式

代理模式的定义:

  代理模式指为其他对象提供一种代理,以控制对这个对象的访问,属于结构型设计模式。

在某种情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理模式的应用场景:

  • 生活中的租房中介、婚姻介绍、经纪人、快递、事物代理、日志监听等,都是代理模式的实际体现。
  • 当无法或不想直接引用某个对象或访问某个对象存在困难时,可以通过代理对象来间接访问。使用代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。

代理模式的UML类图:

由上图可以看到,代理模式一般包含3个角色。

  • 抽象主体角色(ISubject):抽象主题类的主要职责是声明真实主题和代理的共同接口方法,例如途中的dosomething()方法,该类可以是接口,也可以是方法。
  • 真实主题角色(RealSubject):该类也被称为被代理类,该类定义了代理所表示的真实对象,是负责执行系统的真正的业务逻辑对象。
  • 代理主题角色(Proxy):也被称为代理类,其内部持有RealSubject的引用,因此具备完全对RealSubjct的代理权。客户端调用代理对象的方法,也调用被代理对象的方法,但是会在

代理对象前后增加一些处理代理。

  在代码中,一般代理会被理解为代码增强,实际上就是在源代码的逻辑前后增加一些代码逻辑,而使调用在无感。代理模式分为静态代理和动态代理。

从静态代理到动态代理:

  举个例子,有些人到了适婚年龄,会被父母催婚。于是父母就开始到处为子女相亲,比子女自己还着急。下面来看代码实现。

创建顶层接口IPerson的代码如下:

package com.liuyi.designmode.structure.proxy.statics;

/* *
 * @Author liuyi
 * @Description //TODO
 * @Date 2020/11/13 0:09
 **/
public interface IPerson {
    //寻找伴侣抽象方法
    void findLove();
}

张三要找对象,实现Zhangsan类。

/**
 * @ClassName Zhangsan
 * @description:
 * @author:liuyi
 * @Date:2020/11/13 0:11
 class Zhangsan implements IPerson{
    @Override
     findLove() {
        System.out.println("儿子张三提出找对象要求");
    }
}

父亲张老师帮儿子找对象,实现ZhangLaoSan类:


 * @ClassName ZhangLaoSan
 * @description:
 * :liuyi
 * @Date:2020/11/13 0:13
 class ZhangLaoSan  IPerson{

    private Zhangsan zhangsan;

    public ZhangLaoSan(Zhangsan zhangsan){
        this.zhangsan = zhangsan;
    }

    @Override
     findLove() {
        System.out.println("父亲张老三开始帮儿子物色对象");
        zhangsan.findLove();
        System.out.println("开始交往");
    }
}

来看客户端测试代码:

   这样我们就实现了父亲帮助儿子去物色对象的目的(代理),虽然在没有对代理类进行修改的前提下就对代理类实现了功能增强的目的。但是如果现在需要母亲去帮住儿子物色对象,我们又需要创建一个代理类,还有七大姑八大姨,这光是

创建代理类就够呛的,所以这个时候我们就动态代理就闪亮登场了,下面我们来看看使用JDK自带的动态代理在本例中是如如何运用的:

首选创建媒婆类JdkMeipo:

 com.liuyi.designmode.structure.proxy.dynamic;

import com.liuyi.designmode.structure.proxy.statics.IPerson;

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


 * @ClassName JdkMeipo
 * @description:jdk自带的动态代理实现
 * :liuyi
 * @Date:2020/11/13 23:36
 class JdkMeipo  InvocationHandler{

     IPerson target;

    获取处理后的被代理对象
     IPerson getInstance(IPerson iPerson){
        this.target = iPerson;
        Class<? extends IPerson> aClass = iPerson.getClass();
        IPerson iPersonProxy = (IPerson)Proxy.newProxyInstance(aClass.getClassLoader(),aClass.getInterfaces(),(InvocationHandler) this);
        return iPersonProxy;
    }


    @Override
    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {
        before();
        Object invoke = method.invoke(.target,args);
        after();
         invoke;
    }

    private  before(){
        System.out.println("我是媒婆,以及收集到你的需求,开始物色");
    }

     after(){
        System.out.println("双方同意,开始交往");
    }

}

然后创建一个类ZhaoLiu:


 * @ClassName Zhaoliu
 * @description:
 * :liuyi
 * @Date:2020/11/13 23:47
 class Zhaoliu  IPerson {
    @Override
     findLove() {
        System.out.println("符合赵六要求");
    }

}

测试结果如下:

 

 

 代码这样写我们可以发现,只要实现了IPerson接口的单身人士,媒婆(代理类)都可以为其物色对象。

JDK动态代理原理分析:

  不仅知其然,还要知其所以然。既然JDK动态代理的功能如此强大,那么它是如何实现的呢?现在我们来研究一下原理,并模仿JDK动态代理手写一个属于自己的动态代理。

我们知道JDK动态代理采用字节重组,重新生成对象来替代原始对象,以达到动态代理的目的。JDK动态代理生成对象的步骤如下:

  1. 获取被代理对象的引用,并且通过反射获取它的所有接口。
  2. JDK动态代理重新生成一个新的类,并且新的类要实现被代理类实现的所有接口。
  3. 动态生成java代码,新加的业务逻辑方法由一定的逻辑代码调用。
  4. 编译生成新的java代码.class文件。
  5. 重新加载到JVM中运行。

以上过程就叫做字节码重组。JDK中有一个规范,在ClassPath下主要以$开头的.class文件,一般都是自动生成的。那么我们有没有办法看到替代后的对象的"真容呢"?当然可以,

我们在测试类的main方法最前面加上这句话System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");就会在当前工作空间目录的com.sun.proxy下生成

$Proxy0的class文件。通过反编译如下图所示:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.sun.proxy;

import com.liuyi.designmode.structure.proxy.statics.IPerson;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements IPerson {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this,m1,new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void findLove() throws  {
        try {
            super.h.invoke(this,m3,(Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this,m2,(Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this,m0,(Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals",Class.forName("java.lang.Object"));
            m3 = Class.forName("com.liuyi.designmode.structure.proxy.statics.IPerson").getMethod("findLove");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

  我们发现,$Proxy0继承了Proxy类,同时实现了IPerson接口,而且重写了findLove()等方法。在静态块中用反射查找到了目标对象的所有方法,而且保存了所有方法的引用,重写

的方法用反射调用目标对象的方法。我们来分析一下执行过程,我们在测试类中调用findLove()方法,其实是调用的JDK自动生成的代理类($Proxy0)中的findLove()方法。从上面的

$Proxy0类可以查看该方法的内容如下super.h.invoke(this,(Object[])null),此时它就会去调用JdkMeipo的invoke对象。并且你会发现$Proxy0中的每个重写代理对象的方法都是这样

的写法。这样如果我们想对整个类所有的方法进行增强,比如统计各个方法的执行时长,只需要在代理类的invoke方法上下功夫即可。

使用CGLib实现动态代理:

  这里我们使用spring CGlib来实现,首先创建CglibMeipo代理类:

package com.liuyi.designmode.structure.proxy.dynamic.cglib;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @ClassName CGlibMeipo
 * @description:
 * @author:liuyi
 * @Date:2020/11/14 18:06
 */
public class CGlibMeipo implements MethodInterceptor {

    //获取代理类方法
    public Object getInstance(Class<?> clazz) throws Exception{
        //相当于JDK中的Proxy类,是完成代理的工具类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o,Object[] objects,MethodProxy methodProxy) throws Throwable {
        before();
        Object objcet = methodProxy.invokeSuper(o,objects);
        after();
        return objcet;
    }

    private void before(){
        System.out.println("我是媒婆,已经收集到你的需求,开始物色");
    }

    private void after(){
        System.out.println("双方同意,开始交往");
    }

}

创建单身客户类:

 com.liuyi.designmode.structure.proxy.dynamic.cglib;


 * @ClassName Custmoer
 * @description:
 * :liuyi
 * @Date:2020/11/14 18:13
 class Custmoer {
     findLove(){
        System.out.println("符合要求");
    }
}

测试类和结果:

 

 

 CGlib动态代理原理分析:

  我们先来修改一下测试类,生成CGlib生成的代理类class。代码如下:

 org.springframework.cglib.core.DebuggingClassWriter;
 org.springframework.core.io.ClassPathResource;
 org.springframework.core.io.FileSystemResource;
 org.springframework.core.io.Resource;


 * @ClassName Test
 * @description:
 * :liuyi
 * @Date:2020/11/14 18:14
  Test {
    static void main(String[] args)  Exception {
        String property = System.getProperty("user.dir")+"\\src\\main\\java";
        System.out.println(property);
        String debugLocationProperty = DebuggingClassWriter.DEBUG_LOCATION_PROPERTY;
        System.setProperty(debugLocationProperty,property);
        CGlibMeipo cGlibMeipo = new CGlibMeipo();
        Custmoer custmoer = (Custmoer)cGlibMeipo.getInstance(Custmoer.);
        custmoer.findLove();
    }
}

会在当前包下生成三个class文件,如图:

 

 

 通过调试发现,Custmoer$$EnhancerByCGLIB$$6d34774c.class就是CGlib动态生成的代理类,继承了Customer类。Custmoer$$EnhancerByCGLIB$$6d34774c$$FastClassByCGLIB$$85b603b1.class

和Custmoer$$FastClassByCGLIB$$64367e13分别是代理类和被代理类的fastClass,稍后会讲解fastClass是什么。我们先来看看代理类的源码:

//
 Source code recreated from a .class file by IntelliJ IDEA
 (powered by FernFlower decompiler)
//

 org.springframework.cglib.core.ReflectUtils;
 org.springframework.cglib.core.Signature;
 org.springframework.cglib.proxy.Callback;
 org.springframework.cglib.proxy.Factory;
 org.springframework.cglib.proxy.MethodInterceptor;
 org.springframework.cglib.proxy.MethodProxy;

class Custmoer$$EnhancerByCGLIB$$6d34774c extends Custmoer  Factory {
    boolean CGLIB$BOUND;
    static Object CGLIB$FACTORY_DATA;
    final ThreadLocal CGLIB$THREAD_CALLBACKS;
     Callback[] CGLIB$STATIC_CALLBACKS;
     MethodInterceptor CGLIB$CALLBACK_0;
     Object CGLIB$CALLBACK_FILTER;
    final Method CGLIB$findLove$0$Method;
    final MethodProxy CGLIB$findLove$0$Proxy;
     Object[] CGLIB$emptyArgs;
    final Method CGLIB$equals$1final MethodProxy CGLIB$equals$1final Method CGLIB$toString$2final MethodProxy CGLIB$toString$2final Method CGLIB$hashCode$3final MethodProxy CGLIB$hashCode$3final Method CGLIB$clone$4final MethodProxy CGLIB$clone$4$Proxy;

     CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS =  ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.liuyi.designmode.structure.proxy.dynamic.cglib.Custmoer$$EnhancerByCGLIB$$6d34774c");
        Class var1;
        CGLIB$findLove$0$Method = ReflectUtils.findMethods(new String[]{"findLove","()V"},(var1 = Class.forName("com.liuyi.designmode.structure.proxy.dynamic.cglib.Custmoer")).getDeclaredMethods())[0];
        CGLIB$findLove$0$Proxy = MethodProxy.create(var1,var0,"()V","findLove","CGLIB$findLove$0");
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals","(Ljava/lang/Object;)Z","toString","()Ljava/lang/String;","hashCode","()I","clone","()Ljava/lang/Object;"},(var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$equals$1$Method = var10000[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(var1,"equals","CGLIB$equals$1");
        CGLIB$toString$2$Method = var10000[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(var1,"CGLIB$toString$2");
        CGLIB$hashCode$3$Method = var10000[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(var1,"CGLIB$hashCode$3");
        CGLIB$clone$4$Method = var10000[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(var1,"()Ljava/lang/Object;","CGLIB$clone$4"final void CGLIB$findLove$0() {
        super.findLove();
    }

     findLove() {
        MethodInterceptor var10000 = .CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS();
            var10000 = .CGLIB$CALLBACK_0;
        }

        if (var10000 != ) {
            var10000.intercept(this,CGLIB$findLove$0$Method,CGLIB$emptyArgs,CGLIB$findLove$0$Proxy);
        } else {
            .findLove();
        }
    }

    boolean CGLIB$equals$1(Object var1) {
        return .equals(var1);
    }

     equals(Object var1) {
        MethodInterceptor var10000 = ) {
            Object var2 = var10000.intercept(new Object[]{var1},CGLIB$equals$1$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } .equals(var1);
        }
    }

    final String CGLIB$toString$2.toString();
    }

     String toString() {
        MethodInterceptor var10000 = return var10000 != null ? (String)var10000.intercept(int CGLIB$hashCode$3.hashCode();
    }

    int hashCode() {
        MethodInterceptor var10000 = ) {
            Object var1 = var10000.intercept(return var1 == null ? 0 : ((Number)var1).intValue();
        } .hashCode();
        }
    }

    final Object CGLIB$clone$4()  CloneNotSupportedException {
        .clone();
    }

    protected final Object clone()  CloneNotSupportedException {
        MethodInterceptor var10000 = null ? var10000.intercept( MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$4$Proxy;
            }
            break;
        case 1192015562if (var10000.equals("findLove()V"return CGLIB$findLove$0case 1826985398if (var10000.equals("equals(Ljava/lang/Object;)Z"return CGLIB$equals$1case 1913648695if (var10000.equals("toString()Ljava/lang/String;"return CGLIB$toString$2case 1984935277if (var10000.equals("hashCode()I"return CGLIB$hashCode$3$Proxy;
            }
        }

        ;
    }

     Custmoer$$EnhancerByCGLIB$$6d34774c() {
        CGLIB$BIND_CALLBACKS( CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

     CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

     CGLIB$BIND_CALLBACKS(Object var0) {
        Custmoer$$EnhancerByCGLIB$$6d34774c var1 = (Custmoer$$EnhancerByCGLIB$$6d34774c)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            ) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                ) {
                    ;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

     Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        Custmoer$$EnhancerByCGLIB$$6d34774c var10000 =  Custmoer$$EnhancerByCGLIB$$6d34774c();
        CGLIB$SET_THREAD_CALLBACKS((Callback[]) var10000;
    }

     Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS( Callback[]{var1});
        Custmoer$$EnhancerByCGLIB$$6d34774c var10000 =  Object newInstance(Class[] var1,Object[] var2,Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        Custmoer$$EnhancerByCGLIB$$6d34774c var10000 =  Custmoer$$EnhancerByCGLIB$$6d34774c;
        (var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[]));
             var10000;
        defaultthrow new IllegalArgumentException("Constructor not found");
        }
    }

    public Callback getCallback( var1) {
        CGLIB$BIND_CALLBACKS();
        MethodInterceptor var10000;
        (var1) {
        :
            var10000 = .CGLIB$CALLBACK_0;
            ;
        }

        void setCallback( var1,Callback var2) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
        :
        }
    }

     Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(new Callback[]{.CGLIB$CALLBACK_0};
    }

     setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
    }

     {
        CGLIB$STATICHOOK1();
    }
}

可以看到,代理类重写了Customer的所有方法,并且每个方法都有一个代理自动生成的方法与之对应,比如findLove()方法对应的就是CGLIB$findLove$0方法。

 

 

 我们来分析下调用流程,当我们在测试类中调用findLove方法,进入代理类的findLove()方法,代码如下:

.findLove();
        }
    }

这里会调用父类的intercept()方法,至于为什么说是调用父类的intercept()方法,通过查看var10000变量的来源,可以发现就是Callback对象,我们再来看CGlibMeipo类:

 

 Callback就是CGlibMeipo,所以var10000对应的就是代理的对象,那这里调用intercept()自然就来到了代理类的intercept()方法,代码如下:

 

查看invokeSuper方法

 

   上面的代码调用获取代理类对应的FastClass,并执行代理方法。CGLib动态代理执行代理方法的效率之所以被JDK高,就是因为CGLib采用了FastClass机制,它的原理简单来说就是:

为代理类和被代理类各生成一个类,这个类会为代理类或被代理类的方法分配一个index;然后调用对应的方法时,只需要传入对应的index,就可以快速执行该方法,而不是需要根据

反射去调用。因此调用效率要比JDK动态代理高。FastClass并不是跟代理类一起生成的,而是在调用具体方法的时候生成的,并被放到缓冲中。

  所以再回到我们的调用流程,这里会生成两个对应的FastClass,并最终会通过被代理类的FastClass调用被代理类的findLove()方法,然后再执行after()方法,整个调用流程结束。

至此,我们基本清楚了CGLib动态代理的原理,对代码细节感兴趣的小伙伴可以自行深入研究。

CGLib和JDK动态代理的对比分析:

  • JDK动态代理实现了被代理对象的接口,CGLib动态代理继承了被代理对象,也就是说要实现JDK动态代理,被代理的对象必须要有接口,而CGLib不需要。
  • JDK动态代理和CGLib动态代理都在运行时生成字节码,JDK动态代理直接写Class字节码,CGLib动态代理使用ASM框架写Class字节码。CGLib动态代理实现更复杂,生成代理类比JDK动态代理效率低。
  • JDK动态代理调用代理方法是通过反射机制调用的,而CGLib动态代理是通过FastClass机制直接调用方法的,并自带缓存机制,所以CGLib的执行效率要高。

静态代理和动态代理的区别:

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

代理模式的优点:

  • 代理模式能将代理对象与真实被调用目标对象分离。
  • 在一定程度上降低了系统的耦合性,扩展性好。
  • 可以起到保护目标对象的作用。
  • 可以增强目标对象的功能。

代理模式的缺点:

  • 代理模式会造成系统设计中类的数量增加。
  • 在客户端和目标对象中增加一个代理对象,会导致处理请求的速度变慢。
  • 增加了系统的复杂度。

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结