如何用裝飾者模式代理final方法
裝飾者模式
裝飾者模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,它可以在不改變對(duì)象的原有結(jié)構(gòu)的情況下,動(dòng)態(tài)地給對(duì)象添加新的功能和職責(zé)。裝飾者模式的核心思想是使用組合和委托的方式,讓裝飾者類持有一個(gè)被裝飾對(duì)象的引用,并在調(diào)用被裝飾對(duì)象的方法之前或之后添加新的行為。這樣,裝飾者類可以在運(yùn)行時(shí)動(dòng)態(tài)地修改被裝飾對(duì)象的行為,而不需要?jiǎng)?chuàng)建大量的子類。
代碼示例:
// 定義抽象組件類,它是一個(gè)接口,定義了被裝飾對(duì)象和裝飾對(duì)象共同實(shí)現(xiàn)的方法
interface Component {
void operation();
}
// 定義具體組件類,它是一個(gè)實(shí)現(xiàn)了抽象組件接口的具體對(duì)象
class ConcreteComponent implements Component {
public void operation() {
System.out.println("具體組件的操作");
}
}
// 定義裝飾者抽象類,它繼承了抽象組件類,并持有一個(gè)抽象組件的引用
abstract class Decorator implements Component {
protected Component component; // 通過(guò)構(gòu)造函數(shù)傳入被裝飾對(duì)象
public Decorator(Component component) {
this.component = component;
}
public void operation() {
component.operation(); // 可以在調(diào)用被裝飾對(duì)象的方法之前或之后添加新的行為
}
}
// 定義具體裝飾者類,它繼承了裝飾者抽象類,并在其中添加新的行為或功能
class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
public void operation() {
super.operation(); // 調(diào)用父類的方法
addedBehavior(); // 調(diào)用自己的方法
}
public void addedBehavior() {
System.out.println("具體裝飾者A的操作");
}
}
// 定義具體裝飾者類,它繼承了裝飾者抽象類,并在其中添加新的行為或功能
class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
public void operation() {
super.operation(); // 調(diào)用父類的方法
addedBehavior(); // 調(diào)用自己的方法
}
public void addedBehavior() {
System.out.println("具體裝飾者B的操作");
}
}
// 測(cè)試代碼
public class DecoratorPatternDemo {
public static void main(String[] args) {
Component component = new ConcreteComponent(); // 創(chuàng)建被裝飾對(duì)象
Component decoratorA = new ConcreteDecoratorA(component); // 創(chuàng)建具體裝飾者A,并傳入被裝飾對(duì)象
Component decoratorB = new ConcreteDecoratorB(decoratorA); // 創(chuàng)建具體裝飾者B,并傳入具體裝飾者A
decoratorB.operation(); // 調(diào)用具體裝飾者B的方法,輸出如下:
// 具體組件的操作
// 具體裝飾者A的操作
// 具體裝飾者B的操作
}
}
步驟:
- 首先,創(chuàng)建一個(gè)和目標(biāo)類相同的接口,或者如果目標(biāo)類已經(jīng)實(shí)現(xiàn)了一個(gè)接口,你可以直接使用它。這個(gè)接口定義了目標(biāo)類的所有公共方法,包括final方法。
- 然后創(chuàng)建一個(gè)裝飾者類,實(shí)現(xiàn)這個(gè)接口,并在構(gòu)造函數(shù)中傳入一個(gè)目標(biāo)類的實(shí)例。在裝飾者類中,可以為每個(gè)方法添加代理邏輯,比如打印日志、檢查權(quán)限等。然后,可以調(diào)用目標(biāo)類的對(duì)應(yīng)方法,或者直接返回結(jié)果。
- 最后,創(chuàng)建一個(gè)裝飾者類的實(shí)例,并傳入一個(gè)目標(biāo)類的實(shí)例。這樣,就可以通過(guò)裝飾者類來(lái)代理目標(biāo)類的所有方法,包括final方法。
代碼示例:
假設(shè)有一個(gè)目標(biāo)類叫做HelloService,它有一個(gè)final方法叫做sayHello:
// 定義一個(gè)目標(biāo)類,其中有一個(gè)final方法
class Target {
public final void finalMethod() {
System.out.println("目標(biāo)類的final方法");
}
}
// 定義一個(gè)裝飾者抽象類,它持有一個(gè)目標(biāo)對(duì)象的引用
abstract class Decorator {
protected Target target; // 通過(guò)構(gòu)造函數(shù)傳入目標(biāo)對(duì)象
public Decorator(Target target) {
this.target = target;
}
public abstract void operation(); // 定義一個(gè)抽象方法,用于增強(qiáng)目標(biāo)對(duì)象
}
// 定義一個(gè)具體裝飾者類,它繼承了裝飾者抽象類,并在其中添加新的行為或功能
class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Target target) {
super(target);
}
public void operation() {
before(); // 調(diào)用自己的方法
target.finalMethod(); // 調(diào)用目標(biāo)對(duì)象的final方法
after(); // 調(diào)用自己的方法
}
public void before() {
System.out.println("調(diào)用final方法之前");
}
public void after() {
System.out.println("調(diào)用final方法之后");
}
}
// 測(cè)試代碼
public class DecoratorPatternDemo {
public static void main(String[] args) {
Target target = new Target(); // 創(chuàng)建目標(biāo)對(duì)象
Decorator decorator = new ConcreteDecorator(target); // 創(chuàng)建具體裝飾者,并傳入目標(biāo)對(duì)象
decorator.operation(); // 調(diào)用具體裝飾者的方法,輸出如下:
// 調(diào)用final方法之前
// 目標(biāo)類的final方法
// 調(diào)用final方法之后
}
}
這樣做并不是真正意義上的動(dòng)態(tài)代理,因?yàn)槟枰@式地創(chuàng)建裝飾者對(duì)象,并傳入目標(biāo)對(duì)象。而且,如果目標(biāo)類有多個(gè)final方法,您可能需要為每個(gè)方法都創(chuàng)建一個(gè)裝飾者類,這會(huì)增加代碼的復(fù)雜度和冗余。
裝飾者模式和JDK代理的區(qū)別:
- 裝飾者模式和JDK代理都是使用組合而不是繼承來(lái)擴(kuò)展對(duì)象的功能,但是它們的目的和實(shí)現(xiàn)方式不同。
- 裝飾者模式是為了增強(qiáng)對(duì)象本身的功能,而JDK代理是為了控制對(duì)對(duì)象的訪問(wèn),比如添加權(quán)限檢查、日志記錄等。
- 裝飾者模式是客戶端透明的,也就是說(shuō)客戶端不需要知道被裝飾的對(duì)象是怎么被裝飾的,只需要使用它的增強(qiáng)功能即可。而JDK代理是客戶端不透明的,也就是說(shuō)客戶端只能看到代理對(duì)象,而不能直接訪問(wèn)被代理的對(duì)象。
- 裝飾者模式是動(dòng)態(tài)的,也就是說(shuō)可以在運(yùn)行時(shí)根據(jù)需要給對(duì)象添加不同的裝飾者。而JDK代理是靜態(tài)的,也就是說(shuō)在編譯時(shí)就確定了代理對(duì)象和被代理對(duì)象的關(guān)系,不能在運(yùn)行時(shí)改變。
- 裝飾者模式和JDK代理都需要實(shí)現(xiàn)一個(gè)共同的接口,以保證類型的一致性。但是裝飾者模式需要在構(gòu)造函數(shù)中傳入被裝飾的對(duì)象,而JDK代理則需要通過(guò)反射機(jī)制來(lái)創(chuàng)建被代理的對(duì)象。
實(shí)際上可以使用Spring AOP實(shí)現(xiàn)final方法的代理
// 定義一個(gè)目標(biāo)類,包含一個(gè)final方法
public class Target {
public final void sayHello() {
System.out.println("你好,我是目標(biāo)");
}
}
// 定義一個(gè)切面類,用來(lái)編寫增強(qiáng)邏輯
@Aspect
public class AspectDemo {
// 定義一個(gè)前置通知,用@Before注解指定切入點(diǎn)表達(dá)式,匹配目標(biāo)類的final方法
@Before("execution(final void com.example.Target.sayHello())")
public void beforeAdvice() {
System.out.println("建議之前:這是最后的方法");
}
}
// 定義一個(gè)測(cè)試類,用來(lái)創(chuàng)建代理對(duì)象并調(diào)用目標(biāo)方法
public class TestDemo {
public static void main(String[] args) {
// 創(chuàng)建目標(biāo)對(duì)象
Target target = new Target();
// 創(chuàng)建代理工廠
AspectJProxyFactory factory = new AspectJProxyFactory(target);
// 添加切面類
factory.addAspect(AspectDemo.class);
// 獲取代理對(duì)象
Target proxy = factory.getProxy();
// 調(diào)用代理對(duì)象的final方法
proxy.sayHello();
}
}
/**
建議之前:這是最后的方法
你好,我是目標(biāo)**/