設計模式之裝飾器、代理、工廠方法模式
技術標籤:設計模式工廠方法模式裝飾器模式代理模式JDK動態代理設計模式
引言
原文連結:帶你讀懂幾種常見的設計模式 第二彈希望點進去的小夥伴關注一下我的公眾號喲,文末有二維碼,謝謝!
今天的文章繼續介紹設計模式。上一彈中介紹了簡單工廠模式和策略模式,本文將介紹裝飾器模式、代理模式和工廠方法模式。
1、裝飾器模式
裝飾模式的思想是:層層包裹。包裹就是裝飾,那到底什麼是層層包裹呢?有什麼實際例子嗎?
java的io模組中採用了這一種思想,比如下面這段程式碼。
BufferedReader reader =newBufferedReader(newInputStreamReader(newFileInputStream("F:/test.txt")));
BufferedReader包裹了InputStreamReader,而InputStreamReader又包裹了FileInputStream。
首先,FileInputStream具有讀取檔案位元組流的能力,在其外面套了一層InputStreamReader後,讓其具有讀取字元流的能力,再在外面套一層BufferedReader後,又讓其擁有了緩衝讀取的能力。
上面是實際例子,下面我來抽象一下裝飾器模式中有哪些角色。
-
核心能力介面
-
具有核心能力的核心元件(實現了核心能力介面)
-
裝飾器(其本質也是一個具有核心能力的元件,特別之處在於它可以再容納一個元件)
-
具有裝飾能力的元件(繼承了裝飾器)
下面通過程式碼來實現一下這些角色。
核心能力介面。
publicinterfaceCore{
voidsayHello();
}
核心元件。
publicclassCoreComponentimplementsCore{
@Override
publicvoidsayHello(){
System.out.println("CoreComponent say Hello");
}
}
裝飾器。
Decorator類是實現裝飾器模式的核心。Decorator內建了一個Core型別的屬性,而且Decorator也是Core型別,這就是包裹。並且Decorator類的sayHello方法並沒有提供自己的實現,而是直接呼叫了內建Core屬性的實現。
publicabstractclassDecoratorimplementsCore{
privateCore component;
publicvoidsetComponent(Core component){
this.component = component;
}
publicCoregetComponent(){
returncomponent;
}
@Override
publicvoidsayHello(){
this.component.sayHello();
}
}
具有裝飾能力的元件A和B。
這兩個元件分別提供了自己的實現。
publicclassDecoratorAextendsDecorator{
privatevoidsayWhat(){
System.out.println("DecoratorA say what are you doing?");
}
publicDecoratorA(){
}
publicDecoratorA(Core component){
this.setComponent(component);
}
@Override
publicvoidsayHello(){
super.sayHello();
sayWhat();
}
}
publicclassDecoratorBextendsDecorator{
privatevoidsayHow(){
System.out.println("DecoratorB say How are you?");
}
publicDecoratorB(){
}
publicDecoratorB(Core component){
this.setComponent(component);
}
@Override
publicvoidsayHello(){
super.sayHello();
sayHow();
}
}
最後,寫一個main方法執行測試。
publicclassDecoratorTest{
publicstaticvoidmain(String[] args){
DecoratorB cdb =newDecoratorB(newDecoratorA(newCoreComponent()));
cdb.sayHello();
}
}
其輸出如下。
CoreComponentsay Hello
DecoratorA say what are you doing?
DecoratorB say How are you?
2、代理模式
代理模式主要解決在直接訪問物件時帶來的問題,比如,要訪問的物件在遠端機器上。
在面向物件系統中,有些物件由於某些原因(物件建立開銷大、某些操作需要安全控制、需要程序外的訪問),直接訪問會給使用者或者系統結構帶來很多麻煩,所以我們可以在訪問此物件時加上一個對此物件的訪問層。
代理模式中有三個角色:
-
核心能力介面
-
委託類
-
代理類
委託類和代理類都必須實現核心能力介面(即它們必須實現同一介面),委託類肯定是用於執行核心業務方法了,那代理類是幹嘛的呢?
代理類可以做如下事情:
-
預處理訊息
-
過濾訊息
-
把訊息轉發給委託類
-
事後處理訊息
代理模式常用的場景有:windows的快捷方式、spring aop等。熟悉spring框架的讀者一定知道,在service層通過會打上宣告式事務註解,宣告式事務就是通過代理來實現的。
代理模式又分為兩種:靜態代理和動態代理。靜態代理的代理類在程式執行時就建立好了,而動態代理的代理類是在程式執行時動態建立的。
下面以windows快捷方式的案例,分別介紹靜態代理和動態代理。
2.1、靜態代理
開啟idea是一種能力,因此定義為介面,而idea64.exe和idea的快捷方式都具有這種能力,所以實現這個介面。idea64.exe是委託類,idea的快捷方式是代理類,我們一般是用快捷方式去開啟idea的。
定義核心介面。
publicinterfaceOpenIdea{
voidopen();
}
定義委託類。
publicclassIdea64ExeimplementsOpenIdea{
@Override
publicvoidopen(){
System.out.println("通過idea64.exe開啟idea");
}
}
定義代理類。
publicclassIdeaShortcutimplementsOpenIdea{
privateIdea64Exe idea64Exe;
@Override
publicvoidopen(){
if(null== idea64Exe){
idea64Exe =newIdea64Exe();
}
System.out.println("通過idea快捷方式開啟idea");
idea64Exe.open();
}
}
定義main方法執行測試。
publicclassStaticProxyTest{
publicstaticvoidmain(String[] args){
IdeaShortcut proxy =newIdeaShortcut();
proxy.open();
}
}
程式的輸出結果如下。
通過idea快捷方式開啟idea
通過idea64.exe開啟idea
2.2、動態代理
核心介面和委託類跟靜態代理的一樣,而動態代理的代理類由於是動態生成的,所以我們不能在程式執行前就寫好代理類。
具體的做法是,寫一個切面類(切面類不等同於代理類),委託類就好比切入點,在程式執行時,切面類會與委託類相結合(稱為織入)從而生成一個代理類。
定義切面類。
publicclassOpenIdeaAspectimplementsInvocationHandler{
privateOpenIdea target;
publicOpenIdeaAspect(OpenIdea target){
this.target = target;
}
/**
* 這個方法是給動態生成的代理類執行的
*@paramproxy 動態生成的額代理物件
*@parammethod 要執行的方法
*@paramargs 方法的引數
*@return目標物件
*@throwsThrowable
*/
@Override
publicObjectinvoke(Object proxy, Method method, Object[] args)throwsThrowable{
System.out.println("我是動態生成的代理類:"+proxy.getClass().getName());
//定義代理類要做的事
System.out.println("通過快捷方式開啟idea");
//返回目標物件要做的事
returnmethod.invoke(target);
}
}
定義main方法執行測試。
publicclassDynamicProxyTest{
publicstaticvoid main(String[] args) {
// 定義切面類
OpenIdeaAspect aspect =newOpenIdeaAspect(newIdea64Exe());
//在執行時動態生成一個代理類
OpenIdea proxy = (OpenIdea)Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(),
newClass[]{OpenIdea.class},
aspect);
proxy.open();
}
}
輸出結果如下。
我是動態生成的代理類:com.sun.proxy.$Proxy0
通過快捷方式開啟idea
通過idea64.exe開啟idea
3、工廠方法模式
上篇文章中講了簡單工廠模式,最後點出其不符合開閉原則,因此工廠方法模式就是衝著開閉原則來的。
簡單工廠模式中的工廠可以生產所有動物,我們可以改造一下,將工廠定義為一個介面,不同的動物對應不同的工廠,而每一種工廠只能生成一種動物,最後由客戶端決定使用哪種工廠。
說起來還挺好理解的吧,我就直接上程式碼了。
首先Animal、Cat、Dog、Pig類複用簡單工廠模式中對應的類,詳細程式碼請戳這裡設計模式之簡單工廠+策略模式
定義AnimalFactory介面。
publicinterfaceAnimalFactory{
AnimalgetAnimal();
}
定義CatFactory、DogFactory、PigFactory。
publicclassCatFactoryimplementsAnimalFactory{
@Override
publicAnimalgetAnimal(){
returnnewCat();
}
}
publicclassDogFactoryimplementsAnimalFactory{
@Override
publicAnimalgetAnimal(){
returnnewDog();
}
}
publicclassPigFactoryimplementsAnimalFactory{
@Override
publicAnimalgetAnimal(){
returnnewPig();
}
}
定義main方法執行測試。
publicclassFacrotyMethodTest{
publicstaticvoidmain(String[] args){
AnimalFactory factory =newDogFactory();
Animal animal = factory.getAnimal();
animal.sayHello();
}
}
我的二維碼
覺得寫得不錯的小夥伴,掃碼關注一下我的公眾號吧,謝謝呀!