文档章节

Java代理模式详解

商者
 商者
发布于 2016/07/18 14:06
字数 4030
阅读 3
收藏 0
点赞 0
评论 0

代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被为拖累执行后的后续处理。

为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。

更通俗的说,代理解决的问题当两个类需要通信时,引入第三方代理类,将两个类的关系解耦,让我们只了解代理类即可,而且代理的出现还可以让我们完成与另一个类之间的关系的统一管理,但是切记,代理类和委托类要实现相同的接口,因为代理真正调用的还是委托类的方法。

按照代理的创建时期,代理类可以分为两种:
静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
动态:在程序运行时运用反射机制动态创建而成

下面是两个例子说明了静态代理和动态代理的使用方法:

静态代理模式

1
2
3
4
5
6
7
8
9
10
11
12
13
package Proxy;

/**
 * Created by benjamin on 1/15/16.
 */
public interface UserManager {

    void addUser(String userId, String userName);
    void deleteUser(String userId);
    String findUser(String userId);
    void modifyUser(String userId, String userName);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package Proxy;

/**
 * Created by benjamin on 1/15/16.
 */
public class UserManagerImpl implements UserManager {

    public void addUser(String userId, String userName) {
        System.out.println("UserManagerImpl.addUser: " + userId + ": " + userName);
    }

    public void deleteUser(String userId) {
        System.out.println("UserManagerImpl.deleteUser");
    }

    public String findUser(String userId) {
        System.out.println("UserManagerImpl.findUser");
        return "benjamin";
    }

    public void modifyUser(String userId, String userName) {
        System.out.println("UserManagerImpl.modifyUser");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package Proxy;

/**
 * Created by benjamin on 1/15/16.
 */
public class UserManagerProxy implements UserManager {

    private UserManager object;

    // 构造函数传入目标对象
    public UserManagerProxy(UserManager object) {
        this.object = object;
    }

    public void addUser(String userId, String userName) {
        try {

            // 添加基本的日志打印功能
            System.out.println("开始addUser");
            object.addUser(userId, userName);
            System.out.println("成功addUser");

        } catch (Exception e) {
            System.err.println("error addUser");
        }
    }

    public void deleteUser(String userId) {
        object.deleteUser(userId);
    }

    public String findUser(String userId) {
        return object.findUser(userId);
    }

    public void modifyUser(String userId, String userName) {
        object.modifyUser(userId, userName);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package Proxy;

/**
 * Created by benjamin on 1/15/16.
 */
public class Client {

    public static void main(String[] args) {
        UserManager userManager = new UserManagerProxy(new UserManagerImpl());
        userManager.addUser("1111", "张三");

        /**
         * 开始addUser
           UserManagerImpl.addUser: 1111: 张三
           成功addUser
         */
    }
}

相信有一点基础的同学都可以看出静态代理的缺点:
1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。如上的代码只是为UserManager类的访问提供了代理,但是如果还要为其他类如Department类提供代理的话,就需要我们再次添加代理Department的代理类。

这样我们必须要引入动态代理:
在上面的示例中,一个代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象

动态代理模式

原来的接口和实现类都不变,这里就不再重复写了,只是代理类使用了动态代理来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package Proxy;

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

/**
 * Created by benjamin on 1/15/16.
 */
public class UserManagerProxy implements InvocationHandler {

    // 目标对象
    private Object targetObject;

    public Object newProxyInstance(Object targetObject) {
        this.targetObject = targetObject;

        // 第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
        // 第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
        // 第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
        // 根据传入的目标返回一个代理对象
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
    }

    /**
     * 关联的这个实现类的方法被调用时将被执行
     * @param proxy 代理
     * @param method    原对象被调用的方法
     * @param args  方法的参数
     * @return  原方法的返回值
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object ret = null;

        try {

            System.out.println("start invoke-->");

            // 调用目标方法
            ret = method.invoke(targetObject, args);

            System.out.println("success invoke-->");

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("error-->");
            throw e;
        }
        return ret;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package Proxy;

/**
 * Created by benjamin on 1/15/16.
 */
public class Client {

    public static void main(String[] args) {
        UserManager userManager = (UserManager)new UserManagerProxy().newProxyInstance(new UserManagerImpl());
        userManager.addUser("1111", "张三");

        /**
         * start invoke-->
           UserManagerImpl.addUser: 1111: 张三
           success invoke-->
         */
    }
}

AOP模式分析

AOP(AspectOrientedProgramming):将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码—解耦。
正是因为在所有的类里,核心代码之前的操作和核心代码之后的操作都做的是同样的逻辑,因此我们需要将它们提取出来,单独分析,设计和编码,这就是我们的AOP思想。一句话说,AOP只是在对OOP的基础上进行进一步抽象,使我们的类的职责更加单一。

动态代理的优点:
动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强

cglib动态代理实现


JDK自从1.3版本开始,就引入了动态代理,JDK的动态代理用起来非常简单,但是它有一个限制,就是使用动态代理的对象必须实现一个或多个接口 。如果想代理没有实现接口的类可以使用CGLIB包。
CGLIB是一个强大的高性能的代码生成包。它被许多AOP的框架(例如Spring AOP)使用,为他们提供方法的interception(拦截)。Hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联。EasyMock通过使用模仿(moke)对象来测试java代码的包。它们都通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。
  CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
下面通过一个实例来讲解cglib:
 

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.benjamin;

/**
 * 定义一个HelloWorld类
 * 
 * @author benjamin 
 * 
 */
public class HelloWorld {
    public void sayHelloWorld() {
        System.out.println("HelloWorld!");
    }
}


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.benjamin;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * 通过Cglib实现在方法调用前后向控制台输出两句字符串
 * 
 * @author benjamin
 *
 */
public class CglibProxy implements MethodInterceptor {
    //要代理的原始对象
    private Object obj;
    
    public Object createProxy(Object target) {
        this.obj = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.obj.getClass());// 设置代理目标
        enhancer.setCallback(this);// 设置回调
        enhancer.setClassLoader(target.getClass().getClassLoader());
        return enhancer.create();
    }


    /**
     * 在代理实例上处理方法调用并返回结果
     * 
     * @param proxy
     *            代理类
     * @param method
     *            被代理的方法
     * @param params
     *            该方法的参数数组
     * @param methodProxy
     */
    public Object intercept(Object proxy, Method method, Object[] params,
            MethodProxy methodProxy) throws Throwable {
        Object result = null;
        // 调用之前
        doBefore();
        // 调用原始对象的方法
        result = methodProxy.invokeSuper(proxy, params);
        // 调用之后
        doAfter();
        return result;
    }

    private void doBefore() {
        System.out.println("before method invoke");
    }

    private void doAfter() {
        System.out.println("after method invoke");
    }

}


 

1
2
3
4
5
6
7
8
9
10
11
package com.benjamin;

public class HelloWorldTest {

    public static void main(String[] args) {
        HelloWorld helloWorld=new HelloWorld();
        CglibProxy cglibProxy=new CglibProxy();
        HelloWorld hw=(HelloWorld)cglibProxy.createProxy(helloWorld);
        hw.sayHelloWorld();
    }
}



运行结果为:
 

1
2
3
before method invoke
HelloWorld!
after method invoke


 

远程代理的实现

远程代理分为服务端和客户端,都必须存在接口定义的文件。这样客户端只需要通过远程代理就可以拥有存在服务端方法一样的感觉。

共同的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package remoteProxy;

import java.io.Serializable;

/**
 * Created by piqiu on 1/15/16.
 */
public class Call implements Serializable {

    private static final long serialVersionUID = 4924678505695074146L;

    private String className;
    private String methodName;
    private Class[] paramTypes;
    private Object[] params;
    private Object result;

    public Call() {}

    public Call(String className, String methodName, Class[] paramTypes, Object[] params) {
        this.className = className;
        this.methodName = methodName;
        this.paramTypes = paramTypes;
        this.params = params;
    }

    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("{className=" + className).append(",methodName=" + methodName).append(",result=" + result).append("}");
        return sb.toString();
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Class[] getParamTypes() {
        return paramTypes;
    }

    public void setParamTypes(Class[] paramTypes) {
        this.paramTypes = paramTypes;
    }

    public Object[] getParams() {
        return params;
    }

    public void setParams(Object[] params) {
        this.params = params;
    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
package remoteProxy;

import java.rmi.RemoteException;
import java.util.Date;

/**
 * Created by benjamin on 1/15/16.
 */
public interface IHelloService {

    String echo(String msg) throws RemoteException;
    Date getTime() throws RemoteException;
}

服务端代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package remoteProxy.Server;

import remoteProxy.IHelloService;

import java.util.Date;

/**
 * Created by benjamin on 1/15/16.
 */
public class HelloServiceImpl implements IHelloService {

    public String echo(String msg) {
        System.out.println("HelloServiceImpl.echo: " + msg);
        return msg;
    }

    public Date getTime() {
        System.out.println("HelloServiceImpl.getTime: " + new Date());
        return new Date();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package remoteProxy.Server;

import remoteProxy.Call;

import java.io.*;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by benjamin on 1/15/16.
 */
public class SimpleServer {
    private Map remoteObjects = new HashMap();

    /** 把一个远程对象放到缓存中 **/
    public void register(String className, Object remoteObject) {
        remoteObjects.put(className, remoteObject);
    }

    public void service() throws Exception {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        Socket socket = null;
        try {
            ServerSocket serverSocket = new ServerSocket(8888);
            System.out.println("服务器启动......");
            while (true) {
                socket = serverSocket.accept();

                ois = new ObjectInputStream(socket.getInputStream());  // 读取对象
                oos = new ObjectOutputStream(socket.getOutputStream());    // 得到输出流

                Call call = (Call)ois.readObject(); // 接收客户端发送的Call对象

                call = invoke(call);    // 执行完操作拿回结果
                oos.writeObject(call);  // 发送结果

            }
        } finally {
            // 关闭流
            if (ois != null) ois.close();
            if (oos != null) oos.close();
            if (socket != null) socket.close();
        }

    }

    public Call invoke(Call call) {
        Object result = null;
        try {

            String className = call.getClassName();
            String methodName = call.getMethodName();
            Object[] params = call.getParams();
            Class[] paramTypes = call.getParamTypes();
            Class classType = Class.forName(className);

            Method method = classType.getMethod(methodName, paramTypes);
            Object remoteObject = remoteObjects.get(className); // 从缓存中读取相关的缓存对象

            if (remoteObject == null) {
                throw new Exception(className + "的远程对象不存在");
            } else {
                result = method.invoke(remoteObject, params);
            }

        } catch (Exception e) {
            result = e;
        }
        call.setResult(result);
        return call;
    }

    public static void main(String[] args) throws Exception {
        SimpleServer server = new SimpleServer();
        server.register("remoteProxy.IHelloService", new HelloServiceImpl());
        // 启动服务
        server.service();
    }
}

客户端代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package remoteProxy.Client;

import java.io.*;
import java.net.Socket;

/**
 * Created by Benjamin on 1/15/16.
 * Connector 类负责建立与远程服务器的连接,以及接收和发送Socket对象
 */
public class Connector {

    private String host;
    private int port;
    private Socket skt;
    private InputStream is;
    private ObjectInputStream ois;
    private OutputStream os;
    private ObjectOutputStream oos;

    public Connector(String host, int port) throws Exception {
        this.host = host;
        this.port = port;
        connect(host, port);
    }

    /** 发送对象 **/
    public void send(Object obj) throws IOException {
        oos.writeObject(obj);
    }

    /** 接收对象 **/
    public Object receive() throws IOException, ClassNotFoundException {
        return ois.readObject();
    }

    /** 建立与远程服务器的连接 **/
    public void connect() throws Exception {
        connect(host, port);
    }

    public void connect(String host, int port) throws Exception {
        skt = new Socket(host, port);
        os = skt.getOutputStream();
        oos = new ObjectOutputStream(os);
        is = skt.getInputStream();
        ois = new ObjectInputStream(is);
    }

    public void close() { // 关闭连接
        try {
        } finally {
            try {
                ois.close();
                oos.close();
                skt.close();
            } catch (Exception e) {
                System.out.println("Connector.close: " + e);
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package remoteProxy.Client;

import remoteProxy.Call;
import remoteProxy.IHelloService;

import java.rmi.RemoteException;
import java.util.Date;

/**
 * Created by piqiu on 1/15/16.
 */
public class HelloServiceProxy implements IHelloService {

    private String host;
    private int port;

    public HelloServiceProxy(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public String echo(String msg) throws RemoteException {
        Connector connector = null;
        try {

            connector = new Connector(host, port);
            Call call = new Call("remoteProxy.IHelloService", "echo", new Class[]{String.class}, new Object[]{msg});
            connector.send(call);
            call = (Call)connector.receive();
            Object result = call.getResult();
            if (result instanceof Throwable) {
                throw new RemoteException("", (Throwable)result);
            } else {
                return (String)result;
            }
        } catch (Exception e) {
            throw new RemoteException("", e);
        } finally {
            if (connector != null) connector.close();
        }
    }

    public Date getTime() throws RemoteException {
        Connector connector = null;
        try {

            connector = new Connector(host, port);
            Call call = new Call("remoteProxy.IHelloService", "getTime", new Class[]{}, new Object[]{});
            connector.send(call);
            call = (Call)connector.receive();
            Object result = call.getResult();
            if (result instanceof Throwable) {
                throw new RemoteException("", (Throwable)result);
            } else {
                return (Date)result;
            }
        } catch (Exception e) {
            throw new RemoteException("", e);
        } finally {
            if (connector != null) connector.close();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package remoteProxy.Client;

import remoteProxy.Call;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.rmi.RemoteException;

/**
 * Created by piqiu on 1/15/16.
 */
public class ProxyFactory {

    public static Object getProxy(final Class classType, final String host, final int port) {
        InvocationHandler handler = new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Connector connector = null;
                try {
                    connector = new Connector(host, port);
                    Call call = new Call(classType.getName(), method.getName(),
                            method.getParameterTypes(), args);
                    connector.send(call);
                    call = (Call) connector.receive();
                    Object result = call.getResult();
                    if (result instanceof Throwable)
                        throw new RemoteException("",(Throwable) result); // 把异常都转换为RemoteException
                    else
                        return result;
                } finally {
                    if (connector != null)
                        connector.close();
                }
            }
        };
        return Proxy.newProxyInstance(classType.getClassLoader(), new Class[]{classType}, handler);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package remoteProxy.Client;

import remoteProxy.IHelloService;

import java.rmi.RemoteException;

/**
 * Created by piqiu on 1/15/16.
 */
public class SimpleClient {

    public static void main(String[] args) throws RemoteException {
        IHelloService helloService = new HelloServiceProxy("localhost", 8888);
        System.out.println(helloService.echo("hello"));
        System.out.println(helloService.getTime());

        IHelloService helloService1 = (IHelloService)ProxyFactory.getProxy(IHelloService.class, "localhost", 8888);
        System.out.println(helloService1.echo("hello2"));
        System.out.println(helloService.getTime());
    }
}

运行时候先运行服务端,再运行客户端。结果为:

服务端:

1
2
3
4
5
服务器启动......
HelloServiceImpl.echo: hello
HelloServiceImpl.getTime: Fri Jan 15 14:32:52 CST 2016
HelloServiceImpl.echo: hello2
HelloServiceImpl.getTime: Fri Jan 15 14:32:52 CST 2016

客户端:

1
2
3
4
hello
Fri Jan 15 14:32:52 CST 2016
hello2
Fri Jan 15 14:32:52 CST 2016

虚拟代理的实现

根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。

安全代理的实现

用来控制真是对象访问时的权限

智能指引

当调用真实的对象时,代理处理另外一些事。如计算真实对象的引用次数,这样当该对象没有引用时,可以自动释放它。或当第一次引用一个持久对象时,将它装入内存。或在访问一个实例对象前,检查是否已经锁定它,以确保其他对象不能改变它。他们都是通过代理在访问一个对象时附加一些内务处理。

本文转载自:http://benjaminwhx.com/2016/01/15/Java%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F%E8%AF%A6%E8%A7%A3/

共有 人打赏支持
商者

商者

粉丝 39
博文 141
码字总数 43255
作品 0
海淀
架构师
java开发中的常用的设计模式

设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代...

qq_38024548 ⋅ 05/28 ⋅ 0

简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别

转载:原地址http://www.cnblogs.com/zhangchenliang/p/3700820.html 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别 结合简单示例和UML图,讲解工厂模式简单原理。 一、引子 话说...

法斗斗 ⋅ 05/08 ⋅ 0

为什么我墙裂建议大家使用枚举来实现单例。

关于单例模式,我的博客中有很多文章介绍过。作为23种设计模式中最为常用的设计模式,单例模式并没有想象的那么简单。因为在设计单例的时候要考虑很多问题,比如线程安全问题、序列化对单例的...

⋅ 06/10 ⋅ 0

Java 设计模式 之 单例模式 Singleton 实际应用

Java 设计模式 之 单例模式 Singleton 实际应用 http://www.verejava.com/?id=16998954233354

verejava ⋅ 05/24 ⋅ 0

Java篇-接口interface关键字

一 : interface关键字 接口是与类并行的一个概念 Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,...

TianTianBaby223 ⋅ 04/24 ⋅ 0

Java 设计模式(14) —— 复合模式

一、复合模式 模式常一起使用,组合在一个设计解决方案中 复合模式在一个解决方案中结合两个或多个模式,能解决一般性或一系列的问题 二、示例 本次设计模式讲解中无代码示例,由于复合模式是...

磊_lei ⋅ 05/26 ⋅ 0

【唯品会】设计模式在特卖会的应用与思考

设计模式在特卖会的应用与思考 无心之心,道之所存 --《建筑的永恒之道》 1、开篇 之所以讨论设计模式,是因为当前我们都明白它可以提供优雅的解决方案,有利于在团队项目中建立共识,并且无...

暗夜在火星 ⋅ 2016/11/12 ⋅ 0

详解Proxy代理模式的场景分析

代理模式是一个十分优秀的软件架构模式,许多应用都用到了代理模式。代理模式就是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不合适或者不能直接引用另一个对象,...

Java架构 ⋅ 05/30 ⋅ 0

Decorator设计模式的实现中 装饰设计模式学习笔记

装饰设计模式 a)当某个类的某个方法不适应当前业务的需要 思路: 》扩展父类的可供扩展的方法,可以使有,但不优 》装饰设计模式(推荐) 开发步骤: 5)对于满足需求的方法,直接调用被包装的对...

知止内明 ⋅ 04/19 ⋅ 0

Java设计模式之单例设计模式

Java单例设计模式,有多种实现方式,下面介绍一下比较著名的一些实现方式 饿汉式 这种设计模式简单,且没有多线程安全问题,一般实际开发时选用这种方式。 class HungeryDemo{private Hunger...

技术小胖子 ⋅ 2017/11/08 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

从 Confluence 5.3 及其早期版本中恢复空间

如果你需要从 Confluence 5.3 及其早期版本中的导出文件恢复到晚于 Confluence 5.3 的 Confluence 中的话。你可以使用临时的 Confluence 空间安装,然后将这个 Confluence 安装实例升级到你现...

honeymose ⋅ 13分钟前 ⋅ 0

用ZBLOG2.3博客写读书笔记网站能创造今日头条的辉煌吗?

最近两年,著名的自媒体网站今日头条可以说是火得一塌糊涂,虽然从目前来看也遇到了一点瓶颈,毕竟发展到了一定的规模,继续增长就更加难了,但如今的今日头条规模和流量已经非常大了。 我们...

原创小博客 ⋅ 今天 ⋅ 0

MyBatis四大核心概念

本文讲解 MyBatis 四大核心概念(SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper)。 MyBatis 作为互联网数据库映射工具界的“上古神器”,训有四大“神兽”,谓之:Sql...

waylau ⋅ 今天 ⋅ 0

以太坊java开发包web3j简介

web3j(org.web3j)是Java版本的以太坊JSON RPC接口协议封装实现,如果需要将你的Java应用或安卓应用接入以太坊,或者希望用java开发一个钱包应用,那么用web3j就对了。 web3j的功能相当完整...

汇智网教程 ⋅ 今天 ⋅ 0

2个线程交替打印100以内的数字

重点提示: 线程的本质上只是一个壳子,真正的逻辑其实在“竞态条件”中。 举个例子,比如本题中的打印,那么在竞态条件中,我只需要一个方法即可; 假如我的需求是2个线程,一个+1,一个-1,...

Germmy ⋅ 今天 ⋅ 0

Springboot2 之 Spring Data Redis 实现消息队列——发布/订阅模式

一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式,这里利用redis消息“发布/订阅”来简单实现订阅者模式。 实现之前先过过 redis 发布订阅的一些基础概念和操...

Simonton ⋅ 今天 ⋅ 0

error:Could not find gradle

一.更新Android Studio后打开Project,报如下错误: Error: Could not find com.android.tools.build:gradle:2.2.1. Searched in the following locations: file:/D:/software/android/andro......

Yao--靠自己 ⋅ 昨天 ⋅ 0

Spring boot 项目打包及引入本地jar包

Spring Boot 项目打包以及引入本地Jar包 [TOC] 上篇文章提到 Maven 项目添加本地jar包的三种方式 ,本篇文章记录下在实际项目中的应用。 spring boot 打包方式 我们知道,传统应用可以将程序...

Os_yxguang ⋅ 昨天 ⋅ 0

常见数据结构(二)-树(二叉树,红黑树,B树)

本文介绍数据结构中几种常见的树:二分查找树,2-3树,红黑树,B树 写在前面 本文所有图片均截图自coursera上普林斯顿的课程《Algorithms, Part I》中的Slides 相关命题的证明可参考《算法(第...

浮躁的码农 ⋅ 昨天 ⋅ 0

android -------- 混淆打包报错 (warning - InnerClass ...)

最近做Android混淆打包遇到一些问题,Android Sdutio 3.1 版本打包的 错误如下: Android studio warning - InnerClass annotations are missing corresponding EnclosingMember annotation......

切切歆语 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部