裝飾者模式與動態代理
類的方法的增強的方式有很多,最初使用的繼承,但繼承的缺點是後期專案會產生很多的類,增加了專案的複雜度,於是,人們提出了組合,這點在Go語言設計最突出,Go語言甚至去掉了類的繼承,在java的設計模式的,類的增強的設計模式常見有裝飾者模式和動態代理,本文闡述裝飾者模式和動態代理模式的設計技巧.
裝飾者模式
裝飾者模式可以實現對一個類的方法的前後增強,為了更好的闡述該模式的原理,我從一個Service層的新增使用者的方法addUser()展開
首先寫一個介面UserService,中有一個addUser()方法
public interface UserService {
void addUser();
}
實現UserService
public class UserServiceImp implements UserService {
@Override
public void addUser() {
System.out.println("add user ........");
}
}
寫一個裝飾類,前置增強addUser() 方法,指定其構造方法,使得在建立類的時候,傳入UserService,並儲存在屬性中,在重寫的方法中呼叫
public class UserServiceBeforeDecorate implements UserService {
private UserService userService;
public UserServiceBeforeDecorate(UserService userService){
this.userService=userService;
}
@Override
public void addUser() {
//前置增強
System.out.println("before decorate..........");
userService.addUser();
}
}
寫一個UserService的後置增強方法,與上面類似
public class UserServiceAfterDecorate implements UserService {
private UserService userService;
public UserServiceAfterDecorate(UserService userService){
this.userService=userService;
}
@Override
public void addUser() {
userService.addUser();
//後置增強
System.out.println("after decorate ..........");
}
}
寫一個測試類
@Test
public void test3(){
UserServiceBeforeDecorate decorate = new UserServiceBeforeDecorate(new UserServiceAfterDecorate(new UserServiceImp()));
decorate.addUser();
}
這種寫法是不是很熟悉,在java的IO中,就是這樣設計的
// IO的使用
try {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(new File("lhc.txt")));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
但也可以看到,在java的IO的API中,出現了眾多的小類,增加了IO的複雜度,這也是裝飾者模式中不可避免的缺點
動態代理
增強類的方法的另一種方式是使用動態代理,Spring框架的AOP也是基於此,我同樣從一個Service層的新增使用者的方法addUser()展開,看如何前後置增強
使用動態代理,需要寫一個類實現InvocationHandler ,同樣,指定其構造方法,在建立類的時候注入UserService ,並儲存到屬性中,值得關注的是重寫的invoke的方法引數含義
其中method指的是被代理的物件的方法,args指的是被代理的物件的方法的引數,故使用反射執行該方法,並新增前後置增強
public class UserServiceInvocationHandler implements InvocationHandler {
private UserService userService;
public UserServiceInvocationHandler(UserService userService){
this.userService=userService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//對UserService的每一方法的前後置增強
System.out.println("addUser before.........");
Object invoke = method.invoke(userService, args);
System.out.println("addUser after.........");
return invoke;
}
}
寫一個測試,使用Prox的newProxyInstance方法,建立代理物件,需要傳入三個引數
第一個:實現類的類載入器
第二個: 實現類所實現的所有介面
第三個就是上面寫的實現InvocationHandler 的類
@Test
public void test6(){
UserService userServiceImp = new UserServiceImp();
UserService userService = (UserService)Proxy.newProxyInstance(userServiceImp.getClass().getClassLoader(), userServiceImp.getClass().getInterfaces(), new UserServiceInvocationHandler(userServiceImp));
userService.addUser();
}
呼叫器addUser方法,可看到控制檯輸出方法的前後置增強
addUser before.........
add user ........
addUser after.........