代理模式 静态代理、JDK动态代理、Cglib动态代理
1 代理模式
使用代理模式时必须让代理类和被代理类实现相同的接口;
客户端通过代理类对象来调用被代理对象方法时,代理类对象会将所有方法的调用分派到被代理对象上进行反射执行;
在分派的过程中还可以添加前置通知和后置处理。
2 为什么需要使用代理
2.1 需求
现有一个HelloApi接口和一个HelloApi接口的实现类Hello,现在需要统计HelloApi接口中say方法的耗时
package demo_test02; /**
* @author 王杨帅
* @create 2018-08-09 19:20
* @desc
**/
public interface HelloApi { public void say(); }
Hello.java
package demo_test02; /**
* @author 王杨帅
* @create 2018-08-09 19:18
* @desc
**/
public class Hello implements HelloApi { @Override
public void say() {
System.out.println("Hello Fury");
}
}
Hello.java
2.2 思路
思路01 -> 在实现类中实现
思路02 -> 利用静态代理实现
思路03 -> 利用动态代理实现
2.3 解决
2.3.1 在实现类中实现
缺点:
》需要针对方法进行操作,如果有多个方法需要相同的逻辑时工作量巨大
》违背了开闭原则:开闭原则是对扩展开放,但是对修改关闭;为了增加功能把每个方法都修改了,不便于维护
》违背了单一职责原则:每个方法除了完成自己本身的功能,还要计算耗时
开闭原则
开闭原则(OCP)是面向对象设计中“可复用设计”的基石,是面向对象设计中最重要的原则之一,其它很多的设计原则都是实现开闭原则的一种手段。对于扩展是开放的,对于修改是关闭的,这意味着模块的行为是可以扩展的。当应用的需求改变时,我们可以对模块进行扩展,使其具有满足那些改变的新行为。也就是说,我们可以改变模块的功能。对模块行为进行扩展时,不必改动模块的源代码或者二进制代码。模块的二进制可执行版本,无论是可链接的库、DLL或者.EXE文件,都无需改动
开闭原则
单一职责原则
单一职责原则(SRP:Single responsibility principle)又称单一功能原则,面向对象五个基本原则(SOLID)之一。它规定一个类应该只有一个发生变化的原因。该原则由罗伯特·C·马丁(Robert C. Martin)于《敏捷软件开发:原则、模式和实践》一书中给出的。马丁表示此原则是基于汤姆·狄马克(Tom DeMarco)和Meilir Page-Jones的著作中的内聚性原则发展出的。
所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。
单一职责原则
package demo_test02; /**
* @author 王杨帅
* @create 2018-08-09 19:18
* @desc
**/
public class Hello implements HelloApi { @Override
public void say() {
Long start = System.currentTimeMillis();
System.out.println("Hello Fury");
Long end = System.currentTimeMillis();
System.out.println("耗时为:" + (end - start));
} }
HelloApi.java
package demo_test02; /**
* @author 王杨帅
* @create 2018-08-09 19:18
* @desc
**/
public class Test { public static void main(String[] args) { Hello hello = new Hello(); // 01 传统调用方式
hello.say(); // 02 静态调用方式
// StaticProxy staticProxy = new StaticProxy(hello);
// staticProxy.say(); // HelloApi proxy = (HelloApi)new DynamicProxy().getProxy(hello);
// proxy.say(); } }
调用测试
2.3.2 利用静态代理实现
》修改HelloApi的实现类Hello,将实现类中say方法中的计算耗时逻辑去掉
》创建一个类,该类实现了HelloApi接口
》定义一个类型为Hello的成员变量target
》重写say方法,在say方法中利用target成员变量去调用say方法,并在调用你的前后可以增加逻辑处理
》》静态代理实现的缺点
》》》需要针对每一个被代理对象编写一个静态代理类,如果需要进行代理的对象较多,那么工作量将很巨大
》》》静态代理类实现了被代理对象所属类实现的接口,一旦接口发生改变,静态代理类也必须跟着发生变化
package demo_test02; /**
* @author 王杨帅
* @create 2018-08-09 19:18
* @desc
**/
public class Hello implements HelloApi { @Override
public void say() {
// Long start = System.currentTimeMillis();
System.out.println("Hello Fury");
// Long end = System.currentTimeMillis();
// System.out.println("耗时为:" + (end - start));
} }
Hello.java
package demo_test02; import java.util.concurrent.TimeUnit; /**
* @author 王杨帅
* @create 2018-08-09 19:21
* @desc 静态代理类
**/
public class StaticProxy implements HelloApi { /**
* 被代理对象
*/
private Hello hello; public StaticProxy(Hello hello) {
this.hello = hello;
} @Override
public void say() {
Long start = System.currentTimeMillis();
hello.say();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start));
} public Hello getHello() {
return hello;
} public void setHello(Hello hello) {
this.hello = hello;
}
}
StaticProxy.java
package demo_test02; /**
* @author 王杨帅
* @create 2018-08-09 19:18
* @desc
**/
public class Test { public static void main(String[] args) { Hello hello = new Hello(); // 01 传统调用方式
// hello.say(); // 02 静态调用方式
StaticProxy staticProxy = new StaticProxy(hello);
staticProxy.say(); // HelloApi proxy = (HelloApi)new DynamicProxy().getProxy(hello);
// proxy.say(); } }
静态代理测试
2.3.3 利用动态代理实现
》创建一个动态代理类,该类实现了InvocationHandler
》定义一个Object类型的target成员变量
》定义一个getProxy方法,该方法接收一个Object类型对象【就是被代理对象】;方法体中初始化target成员变量,并返回一个动态代理对象
技巧01:调用Proxy的newProxyInstance 去创建动态代理对象,该方法接收三个参数,分别是:
ClassLoader loader -> 被代理对象的类加载器【PS: 可以通过被加载对象的类类型去获取类加载器】
Class<?>[] interfaces -> 被代理对象实现的接口组成的数组【PS: 可以通过被加载对象的类类型去获取实现的接口】
InvocationHandler h -> 动态代理类实例【PS: 通过this传入自定义的动态代理类实例即可】
/**
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler.
*
* <p>{@code Proxy.newProxyInstance} throws
* {@code IllegalArgumentException} for the same reasons that
* {@code Proxy.getProxyClass} does.
*
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
* @return a proxy instance with the specified invocation handler of a
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
* @throws IllegalArgumentException if any of the restrictions on the
* parameters that may be passed to {@code getProxyClass}
* are violated
* @throws SecurityException if a security manager, <em>s</em>, is present
* and any of the following conditions is met:
* <ul>
* <li> the given {@code loader} is {@code null} and
* the caller's class loader is not {@code null} and the
* invocation of {@link SecurityManager#checkPermission
* s.checkPermission} with
* {@code RuntimePermission("getClassLoader")} permission
* denies access;</li>
* <li> for each proxy interface, {@code intf},
* the caller's class loader is not the same as or an
* ancestor of the class loader for {@code intf} and
* invocation of {@link SecurityManager#checkPackageAccess
* s.checkPackageAccess()} denies access to {@code intf};</li>
* <li> any of the given proxy interfaces is non-public and the
* caller class is not in the same {@linkplain Package runtime package}
* as the non-public interface and the invocation of
* {@link SecurityManager#checkPermission s.checkPermission} with
* {@code ReflectPermission("newProxyInPackage.{package name}")}
* permission denies access.</li>
* </ul>
* @throws NullPointerException if the {@code interfaces} array
* argument or any of its elements are {@code null}, or
* if the invocation handler, {@code h}, is
* {@code null}
*/
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
} /*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs); /*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
} final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
》重写invoke方法,在方法体通过mehtod的invoke方法去调用被代理对象的方法【PS: 利用反射实现的】
》》坑01:获取到的动态代理类的类型是Ojbect类型,必须进行类型转换成对应的类型
》》动态代理类实现的好处
》》》自定义动态代理类,被代理对象所属类所实现的接口变动时代理类也无需变动,因为动态代理是通过反射的方式实现被代理对象所属类所实现的接口的
》》》符合开闭原则,通过代理实现新功能,没有侵入到原有代码,也不用破坏原来的代码结构,完美的扩展方案
package demo_test02; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.TimeUnit; /**
* @author 王杨帅
* @create 2018-08-09 19:26
* @desc 动态代理类
**/
public class DynamicProxy implements InvocationHandler { /**
* 被代理对象
*/
private Object target; /**
* 利用JDK的动态代理创建代理对象
* @param target
* @return
*/
public Object getProxy(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Long start = System.currentTimeMillis();
Object result = method.invoke(target, args);
TimeUnit.SECONDS.sleep(1);
Long end = System.currentTimeMillis();
System.out.println("花费的时间为:" + (end - start));
return result;
} public Object getTarget() {
return target;
} public void setTarget(Object target) {
this.target = target;
}
}
DynamicProxy.java
package demo_test02; /**
* @author 王杨帅
* @create 2018-08-09 19:18
* @desc
**/
public class Test { public static void main(String[] args) { Hello hello = new Hello(); // 01 传统调用方式
// hello.say(); // 02 静态调用方式
// StaticProxy staticProxy = new StaticProxy(hello);
// staticProxy.say(); HelloApi proxy = (HelloApi)new DynamicProxy().getProxy(hello);
proxy.say(); } }
调用测试
3 动态代理
3.1 动态代理类编程步骤
》通过实现InvocationHandler接口来自定义自己的InvocationHandler;
3.2 繁琐方法
package demo_test02; import java.lang.reflect.*; /**
* @author 王杨帅
* @create 2018-08-09 19:59
* @desc
**/
public class Test02 { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
StudentImpl student = new StudentImpl(); /**
* 00 实现InvocationHandler来创建自己的动态代理类
* 01 获取动态代理类的类类型
* 02 获取动态代理类的构造器
* 03 创建动态代理类的实例
* 04 利用动态代理对象去调用被代理对象的方法
*/
Class<?> studentProxyClass = Proxy.getProxyClass(Student.class.getClassLoader(), Student.class); Constructor<?> studentProxyClassConstructor = studentProxyClass.getConstructor(InvocationHandler.class); Student studentProxy = (Student)studentProxyClassConstructor.newInstance(new StudentDynamicProxy(student)); studentProxy.study(); } interface Student {
void study();
} static class StudentImpl implements Student { @Override
public void study() {
System.out.println("I am studying dynamic proxy of java.");
}
} /**
* 自定义动态代理类
*/
static class StudentDynamicProxy implements InvocationHandler { /**
* 被代理对象
*/
private Object target; public StudentDynamicProxy(Object target) {
this.target = target;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置处理");
Object result = method.invoke(target, args);
System.out.println("后置处理");
return result;
}
} }
3.3 简便方法
package demo_test02; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; /**
* @author 王杨帅
* @create 2018-08-09 20:13
* @desc
**/
public class Test03 { public static void main(String[] args) {
StudentImpl student = new StudentImpl();
Student studentProxy = (Student)new StudentDynamicProxy().getDynamicProxyObject(student);
studentProxy.hello();
} interface Student {
void hello();
} static class StudentImpl implements Student { @Override
public void hello() {
System.out.println("你好,王杨帅。");
}
} static class StudentDynamicProxy implements InvocationHandler { private Object target; public Object getDynamicProxyObject(Object target) {
this.target = target;
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置处理");
Object result = method.invoke(target, args);
System.out.println("后置处理");
return result;
}
} }
3.4 参考博文
4 代理模式
4.1 静态代理
技巧01:静态代理的目标者和代理者都需要实现相同的接口
》接口:代理者和目标者需要实现的接口
package cn.xinagxu.static_proxy; /**
* @author 王杨帅
* @create 2018-08-19 20:27
* @desc
**/
public interface ISservice {
String someMethod01();
void someMethod02();
}
ISservice.java
》目标者:被代理对象
package cn.xinagxu.static_proxy; /**
* @author 王杨帅
* @create 2018-08-19 20:25
* @desc
**/
public class SomeService implements ISservice { public String someMethod01() {
return "someMethod01";
} public void someMethod02() {
System.out.println("someMethod02");
} }
SomeService.java
》代理者:代理目标者需要用到的代理类
package cn.xinagxu.static_proxy; /**
* @author 王杨帅
* @create 2018-08-19 20:26
* @desc
**/
public class StaticProxy implements ISservice { SomeService target; public StaticProxy(SomeService target) {
this.target = target;
} public String someMethod01() {
String result = target.someMethod01();
return result.toUpperCase();
} public void someMethod02() {
target.someMethod02();
}
}
StaticProxy.java
》测试类
package cn.xinagxu.static_proxy; /**
* @author 王杨帅
* @create 2018-08-19 20:32
* @desc
**/
public class StaticProxtTest { public static void main(String[] args) { SomeService target = new SomeService(); StaticProxy proxy = new StaticProxy(target); String result = proxy.someMethod01(); System.out.println(result); proxy.someMethod02(); } }
StaticProxtTest.java
4.2 JDK动态代理
技巧01:jdk动态代理不需要自己编写代理类,因为时直接使用Proxy类来创建代理对象的;目标者的类任然需要实现一个接口
》接口:目标者需要实现的接口
package cn.xinagxu.dynamic_proxy; /**
* @author 王杨帅
* @create 2018-08-19 20:27
* @desc
**/
public interface ISservice {
String someMethod01();
void someMethod02();
}
ISservice.java
》目标者
package cn.xinagxu.dynamic_proxy; /**
* @author 王杨帅
* @create 2018-08-19 20:25
* @desc
**/
public class SomeService implements ISservice { public String someMethod01() {
return "someMethod01";
} public void someMethod02() {
System.out.println("someMethod02");
} }
SomeService.java
》测试类
package cn.xinagxu.dynamic_proxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; /**
* @author 王杨帅
* @create 2018-08-19 20:40
* @desc
**/
public class DynamicProxyTest { public static void main(String[] args) { final SomeService target = new SomeService(); ISservice proxy = (ISservice) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("someMethod01".equals(method.getName())) {
String str = (String) method.invoke(target, args);
return str.toUpperCase();
} else {
Object result = method.invoke(target, args);
return result;
} }
}
); System.out.println(proxy.someMethod01()); proxy.someMethod02(); } }
DynamicProxyTest.java
4.3 Cglib动态代理
技巧01:Cglib动态代理不需要接口,借助 Enhancer 类来创建代理对象,借助 MethodInterceptor 接口的 intercept 方法来实现增强逻辑
技巧02:Enhancer 就相当于JDK动态代理中的Proxy,MethodInterceptor 接口的 intercept 方法就相当于JDK动态代理中 InvocationHandler 中的 invoke 方法
技巧03:使用Cglib动态代理时需要引入外部依赖cglib
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.7</version>
</dependency>
》目标者
package cn.xinagxu.cglib_proxy; /**
* @author 王杨帅
* @create 2018-08-19 20:25
* @desc
**/
public class SomeService { public String someMethod01() {
return "someMethod01";
} public void someMethod02() {
System.out.println("someMethod02");
} }
SomeService.java
》代理类工厂:用于创建代理对象的【PS: 可以不需要的,直接利用内部类实现】
package cn.xinagxu.cglib_proxy; import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; import javax.xml.ws.Service;
import java.lang.reflect.Method; /**
* @author 王杨帅
* @create 2018-08-19 21:03
* @desc
**/
public class CglibFactory implements MethodInterceptor { private SomeService target; public CglibFactory(SomeService someService) {
this.target = someService;
} public CglibFactory() {
} // 创建代理对象的方法
public SomeService createProxy() { // 01 创建一个增强器
Enhancer enhancer = new Enhancer(); // 02 设置增强方
enhancer.setSuperclass(target.getClass()); // 03 接口回调方法
enhancer.setCallback(this); // 04 返回代理对象
return (SomeService) enhancer.create(); } // 跟JDK动态代理的invoke方法差不多
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { if ("someMethod01".equals(method.getName())) {
String str = (String) method.invoke(target, objects);
return str.toUpperCase();
} else {
Object result = method.invoke(target, objects);
return result;
} } }
CglibFactory.java
》测试类
package cn.xinagxu.cglib_proxy; /**
* @author 王杨帅
* @create 2018-08-19 21:12
* @desc
**/
public class CglibProxyTest { public static void main(String[] args) { SomeService target = new SomeService(); // 创建代理对象
SomeService proxy = new CglibFactory(target).createProxy(); System.out.println(proxy.someMethod01()); proxy.someMethod02(); } }
CglibProxyTest.java
4.4 三种代理模的总结
4.4.1 静态代理
原材料:目标者、代理者、接口
特点:迅速、目标者和代理者需要实现同一个接口
比喻:
目标者 -> 公司
代理者 -> 法律顾问
4.4.2 JDK动态代理
原材料:目标者、接口
特点:只需要目标者实现接口、目标者必须是final类型、代理者的类型必须是接口类型
目标者 -> 个人
代理者 -> 事务所
4.4.3 Cglib动态代理
原材料:目标者、cglib依赖
特点:只需要目标者(目标者类型可以是类也可以是接口)、目标者不能是final类型、需要引入cglib依赖
目标者 -> 个人
代理者 -> 儿子
4.4.4 三种代理方式源代码

代理模式 静态代理、JDK动态代理、Cglib动态代理的更多相关文章
- 代理模式(静态代理、JDK动态代理原理分析、CGLIB动态代理)
代理模式 代理模式是设计模式之一,为一个对象提供一个替身或者占位符以控制对这个对象的访问,它给目标对象提供一个代理对象,由代理对象控制对目标对象的访问. 那么为什么要使用代理模式呢? 1.隔离,客户端 ...
- 代理模式:利用JDK原生动态实现AOP
代理模式:利用JDK原生动态实现AOP http://www.cnblogs.com/qiuyong/p/6412870.html 1.概述 含义:控制对对象的访问. 作用:详细控制某个(某类)某对象 ...
- java 设计模式之单利模式以及代理模式(静态)
1:单利模式: public class Singleton { private static Singleton uniqueInstance = null; private Singleton() ...
- 分享知识-快乐自己:三种代理(静态、JDK、CGlib 代理)
1):代理模式(静态代理)点我下载三种模式源码 代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. 静态代理由 业务实现类.业务代理类 两部分组成 ...
- java 代理模式-静态代理与动态代理
最近在研究SpringAOP,当然要学习AOP就要知道这么健硕.强大的功能的背后究竟隐藏着怎样不可告人的“秘密”?? 接下来就是查阅了许多资料详细的研究了一下Java的代理模式,感觉还是非常非常重要的 ...
- Java代理模式/静态代理/动态代理
代理模式:即Proxy Pattern,常用的设计模式之一.代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问. 代理概念 :为某个对象提供一个代理,以控制对这个对象的访问. 代理类和委 ...
- 【Java】代处理?代理模式 - 静态代理,动态代理
>不用代理 有时候,我希望在一些方法前后都打印一些日志,于是有了如下代码. 这是一个处理float类型加法的方法,我想在调用它前打印一下参数,调用后打印下计算结果.(至于为什么不直接用+号运算, ...
- Java中的代理模式--静态代理和动态代理本质理解
代理模式定义:为其他对象提供了一种代理以控制对这个对象的访问. 代理模式的三种角色: Subject抽象主题角色:抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求. Real ...
- Java代理模式——静态代理模式
一:代理模式 代理模式的作用是:为其他对象提供一种代理以控制这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 二:代理模式设计 ...
随机推荐
- 关于 self = [super init];
[plain] view plaincopyprint? - (id)init { self = [super init]; // Call a designated initializer here ...
- 实现一个scnprinf
#include <stdio.h> #include <stdarg.h> /* 该函数ret = min(size, 实际写入长度) - 1,即ret永远小于size * ...
- 剑指offer-第五章优化时间和空间效率(数组中出现次数超过一半的数字)
题目:输入一个数组,找出一个数字,它在数组中出现的次数超过数组的一半. 题目规定如果可以改变数组中元素的位置. 思路1:如果数组是排序的,那么中间元素的位置不就是次数超过数组一半的元素吗?是的,因此我 ...
- 剑指offer-第四章解决面试题的思路(栈的压入和弹出序列)
题目:输入两个整数序列,第一个序列表示栈的压入序列,请判断第二个序列是否为弹出序列. 思路:定义两个指针sPush和sPop分别指向两个整数序列的开头,借助一个辅助的栈,将第一个序列的数据依次压入栈中 ...
- Nginx 反向代理与负载均衡详解
序言 Nginx的代理功能与负载均衡功能是最常被用到的,关于nginx的基本语法常识与配置已在Nginx 配置详解中有说明,这篇就开门见山,先描述一些关于代理功能的配置,再说明负载均衡详细. Ngin ...
- angular中的 input select 值绑定无效,以及多出一个空白选项问题
问题: <!-- 问题标签 --> <select ng-model="sortType"> <option value="1"& ...
- numpy之初探排序和集合运算
排序 排序 numpy与python列表内置的方法类似,也可通过sort方法进行排序. 用法如下: In [1]: import numpy as np In [2]: x = np.random.r ...
- junit基础学习
学习地址一:http://blog.csdn.net/andycpp/article/details/1327147/ 学习地址二:http://blog.csdn.net/zen99t/articl ...
- GOF23设计模式之建造者模式(builder)
一.建造者模式概述 建造者模式的本质: 1.分离了对象子组件的单独构造(由Builder负责)和装配(由Director负责).从而可以构造出复杂的对象.这个模式适用于:某个对象的过程复杂的情况下使用 ...
- 多线程使用信号量sem_init,sem_wait,sem_post
信号量的主要函数有: int sem_init(sem_t *sem,int pshared,unsigned int value); int sem_wait(sem_t *sem); int se ...