1. 程式人生 > 其它 >設計模式之裝飾器、代理、工廠方法模式

設計模式之裝飾器、代理、工廠方法模式

技術標籤:設計模式工廠方法模式裝飾器模式代理模式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、代理模式

代理模式主要解決在直接訪問物件時帶來的問題,比如,要訪問的物件在遠端機器上。

在面向物件系統中,有些物件由於某些原因(物件建立開銷大、某些操作需要安全控制、需要程序外的訪問),直接訪問會給使用者或者系統結構帶來很多麻煩,所以我們可以在訪問此物件時加上一個對此物件的訪問層。

代理模式中有三個角色:

  • 核心能力介面

  • 委託類

  • 代理類

委託類和代理類都必須實現核心能力介面(即它們必須實現同一介面),委託類肯定是用於執行核心業務方法了,那代理類是幹嘛的呢?

代理類可以做如下事情:

  1. 預處理訊息

  2. 過濾訊息

  3. 把訊息轉發給委託類

  4. 事後處理訊息

代理模式常用的場景有: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();
}
}

我的二維碼

覺得寫得不錯的小夥伴,掃碼關注一下我的公眾號吧,謝謝呀!