創(chuàng)建一個(gè)新的對(duì)象躲因,將原對(duì)象作為新對(duì)象的屬性。使用原對(duì)象的地方忌傻,自動(dòng)轉(zhuǎn)為使用新對(duì)象
大脉,同樣的功能方法,新對(duì)象可選擇增強(qiáng)原對(duì)象的功能水孩,也可選擇重新實(shí)現(xiàn)原對(duì)象的功能
為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問镰矿。
- 適配器:使用B接口(港版電腦),不能直接對(duì)接A接口(墻上的電插頭)俘种,這時(shí)候需要加一個(gè)B到A的適配器(轉(zhuǎn)換頭)秤标。
public BAdapter implements/extends B {
private A a;
public BAdapter(A a) {
this.a = a;
}
public void b() { // 名稱為外部的接口名稱绝淡,內(nèi)部轉(zhuǎn)換為,實(shí)際的接口
a.a();
}
}
- 代理:為原對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問苍姜。
原對(duì)象和代理對(duì)象都實(shí)現(xiàn)同一接口
牢酵。
對(duì)于外部調(diào)用者來說只關(guān)心調(diào)用操作是否被執(zhí)行,而不會(huì)關(guān)心本次調(diào)用是被直接執(zhí)行的還是被代理者間接執(zhí)行的衙猪。所以馍乙,aop中,獲取進(jìn)行了aop功能增強(qiáng)的類垫释,
是通過接口獲人扛瘛(不能通過具體類名獲取,ioc容器里面沒有原來實(shí)現(xiàn)類的bean棵譬,只有代理類的bean)铁追,Spring自動(dòng)轉(zhuǎn)換為調(diào)用代理類
。
public AProxy implements/extends A {
private A a;
public AProxy(A a) {
this.a = a;
}
public void a() { // 只做功能增強(qiáng)茫船,接口名稱和主要功能不變
this.a.a();
}
}
這里最重要的就是:代理類持有被代理類的一個(gè)實(shí)例琅束,無論代理類是繼承還是接口實(shí)現(xiàn)
- 裝飾器:把核心功能和附加功能給分開了。裝飾器類和原實(shí)現(xiàn)類算谈,都
實(shí)現(xiàn)的同一接口 / 繼承自同一個(gè)類
涩禀。裝飾器不但實(shí)現(xiàn)原抽象接口,還聚合了原抽象接口(即持有一個(gè)原抽象接口的具體實(shí)現(xiàn))
然眼。半透明的裝飾器約等于適配器艾船。手抓餅加雞蛋加生菜加培根。
image.png
Decorator模式讓調(diào)用者自己創(chuàng)建核心類高每,然后組合各種功能屿岂。Proxy模式?jīng)Q不能讓調(diào)用者自己創(chuàng)建再組合,否則就失去了代理的功能鲸匿。Proxy模式讓調(diào)用者認(rèn)為獲取到的是核心類接口爷怀,但實(shí)際上是代理類
。
問題
class UserService {
@AutoWired
OrderService orderService;
public void test() {
log.info("哈哈哈哈哈");
log.info("orderService: {}", orderService);
};
}
- 通過aop生成的
UserService代理對(duì)象
的orderService屬性是不是null?
是的带欢。原因是代理對(duì)象是一個(gè)新的對(duì)象运授,和原來的被代理的UserService不是同一個(gè)對(duì)象,
這個(gè)代理對(duì)象沒有經(jīng)過依賴注入乔煞,所以orderService屬性是null
- 調(diào)用UserService代理對(duì)象的test方法吁朦,打印的orderService是不是null
不是。
代理對(duì)象持有target的是一個(gè)spring的bean
渡贾,是通過依賴注入的bean逗宜。所以說代理模式,最重要的是:代理類持有被代理類的一個(gè)實(shí)例,無論代理類是繼承還是接口實(shí)現(xiàn)
class UserServiceProxy extends UserService {
UserService target;
public void test() {
// aop增強(qiáng)邏輯:從切點(diǎn)緩存中獲取
target.test();
};
}