設計模式之代理模式(java)
阿新 • • 發佈:2018-12-17
1、概念
為其他物件提供一種代理以控制對這個物件的訪問。在某些情況下,一個物件不適合或者不能直接引用另一個物件,而代理物件可以在客戶端和目標物件之間起到中介的作用。
2、UML類圖
3、java程式碼實現
抽象角色:表演介面(Act)
public interface Act {
void act();
}
具體角色:演員類(Actor),實現表演介面(Act)
public class Actor implements Act { private String name; @Override public void act() { System.out.println("我是演員,我會噴火!!!"); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
代理角色:代理類(StaticProxy),實現表演介面(Act),維護一個表演介面(Act)的引用
public class StaticProxy implements Act {
private Act target;
public StaticProxy(Act target) {
this.target = target;
}
@Override
public void act() {
System.out.println("我是代理人,下面是演員的表演!!!");
target.act();
}
}
測試
@Test public void testStaticProxy(){ Act target = new Actor(); StaticProxy proxy = new StaticProxy(target); proxy.act(); }
測試結果
我是代理人,下面是演員的表演!!!
我是演員,我會噴火!!!
以上程式碼用"代理模式"實現了的一個簡單案列,這種代理模式叫做"靜態代理",它的一個明顯的缺點就是介面發生變化,代理物件的程式碼也要進行相應的維護。除了"靜態代理"外,java還存在其他兩種"代理模式",分別是"動態代理"和"Cglib代理"
動態代理(jdk代理或介面代理):目標物件必須實現一個或多個介面
public class ProxyFactory { private Object target; public ProxyFactory(Object target) { this.target = target; } public Object newProxyInstance(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), (Object proxy, Method method, Object[] args) -> { System.out.println("動態代理(JDK代理)"); Object returnValue = method.invoke(target, args); return returnValue; } ); } }
測試及測試結果
@Test
public void testJdkProxy(){
Act target = new Actor();
ProxyFactory factory = new ProxyFactory(target);
Act act = (Act) factory.newProxyInstance();
act.act();
}
動態代理(JDK代理)
我是演員,我會噴火!!!
Cglib代理:無需實現介面
舞者類(Dancer):沒有實現任何介面
public class Dancer {
public void dance() {
System.out.println("我是舞者,我會跳舞!!!");
}
}
Cglib代理類
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
public Object newProxyInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib代理");
Object returnValue = method.invoke(target, objects);
return returnValue;
}
}
測試及測試結果
@Test
public void testCglibProxy() {
Dancer dancer = new Dancer();
CglibProxy cglibProxy = new CglibProxy(dancer);
Dancer proxy = (Dancer) cglibProxy.newProxyInstance();
proxy.dance();
}
Cglib代理
我是舞者,我會跳舞!!!
4、總結
三種代理模式各有優缺點,主要在於目標物件是否實現了介面。
例如:在Spring中,加入容器的目標物件實現了介面,就用jdk代理;沒有就用cglib代理。