欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
Visitor模式的可行與不可愛(ài)
 

Visitor模式的可行與不可愛(ài)

作者/來(lái)源: Bruce Zhang

 

可否使用Visitor模式實(shí)現系列二的例子呢?經(jīng)過(guò)我的悉心研究,結論是Visitor模式對于本例而言,可行但不可愛(ài)!

我們先看看本例最初的類(lèi)圖:

我們可以將這個(gè)類(lèi)圖看作是一個(gè)樹(shù)形結構。那么各個(gè)類(lèi)即可以看作是樹(shù)的枝葉節點(diǎn)了。這樣一說(shuō),似乎和Composite模式有些關(guān)系了。其實(shí)不然,因為我所謂的樹(shù)枝節點(diǎn),如AudioMedia類(lèi),與MP3及WAV類(lèi)并非是聚合的關(guān)系。認識到這一點(diǎn)很重要,為避免混淆視聽(tīng),我將這些類(lèi)只稱(chēng)作節點(diǎn)好了,就別提樹(shù)枝樹(shù)葉,避免產(chǎn)生誤會(huì )。

而Play()以及Resize()方法,就可以認為是這些節點(diǎn)共同的行為,然而其行為的內涵則是不相同的。也就是說(shuō),RM和MPEG雖然都有Play()方法,但Play的操作不同。也就是說(shuō),現在,我們可能會(huì )為這些不同的媒體類(lèi)型不斷提供更多的行為。而Visitor模式呢?其優(yōu)勢就在于:

為各節點(diǎn)增加新的行為,變得非常的容易。

也就是說(shuō),Visitor模式對于本例而言,是可行的。但這破壞了一個(gè)前提,就是如果適用Visitor模式必須要更改原來(lái)的設計架構,除非你愿意再為這些媒體類(lèi)分別進(jìn)行Wrap!好吧,既然是出于研究目的,我們就來(lái)看看Visitor模式的應用。修改前提為:重構原來(lái)的設計,使舊有的媒體播放器,能夠非常容易地擴充行為。

使用Visitor模式,最大的特點(diǎn)是將被訪(fǎng)問(wèn)對象(通常稱(chēng)為節點(diǎn)或元素)的行為,與其對象分離。并用專(zhuān)門(mén)的Visitor對象,管理節點(diǎn)的行為。在本例中,抽象節點(diǎn)包括:AudioMedia和VedioMedia。其下的具體節點(diǎn)分別為:MP3、WAV和RM、MPEG。那么在Vistor對象,就應該包括四個(gè)訪(fǎng)問(wèn)行為。

是這樣嗎?看來(lái)還有些問(wèn)題。從實(shí)際需求來(lái)分析,本例的節點(diǎn)應分為兩大類(lèi)型:視頻媒體和音頻媒體。而這兩類(lèi)媒體的行為方法,可能是不相同的。例如,視頻媒體除了要求Play()方法外,可能還需要Resize()方法。而音頻媒體就沒(méi)有必要使用Resize()方法了,反而會(huì )需要視頻媒體不需要的方法ShowScript()。因此結論是:我們應該分別為AudioMedia和VedioMedia建立不同的抽象Visitor類(lèi)。最后獲得應用Visitor模式的類(lèi)圖如下:

其實(shí)此時(shí)IMedia接口已經(jīng)可以去掉,我之所以保留出于兩個(gè)目的:

1、為兩種類(lèi)型媒體保持類(lèi)型的抽象;

2、可以提供兩種類(lèi)型媒體同時(shí)具有,且不需要Visitor的行為;

(注:此時(shí)的Play方法其實(shí)可以放到IMedia接口中。我仍然將其放到Visitor的目的是,便于說(shuō)明Visitor模式,同時(shí)通過(guò)這種方式,使對Play方法的修改較為容易)

請大家注意上圖的類(lèi)圖左側,即我定義的媒體類(lèi)型對象區,在這種Visitor模式設計的前提下,對于類(lèi)型的行為來(lái)說(shuō),是非常穩定的。即:無(wú)論你要為這四種媒體類(lèi)型增加什么行為,都不需要修改該區域的任何類(lèi)或接口;而你只需要在Visitor下增加行為的具體Visitor類(lèi)即可。這就符合了OO思想中非常著(zhù)名的開(kāi)—閉原則。左區即為相對的閉區間(我不能說(shuō)是絕對的對修改關(guān)閉,因此,我才用虛線(xiàn)來(lái)作界定),而右區則為相對的開(kāi)區間。

還是來(lái)看看源代碼:

首先是被訪(fǎng)問(wèn)的類(lèi)型:

public

 

interface IMedia

{}

public

 

abstract

 

class AudioMedia,IMedia

{

 

public

 

abstract

 

void Accept(AudioVisitor visitor);

}

public

 

class MP3:AudioMedia

{

 

public

 

override

 

void Accept(AudioVisitor visitor)

 

{

  visitor.VisitMP3();

 }

}

public

 

class WAV:AudioMedia

{

 

public

 

override

 

void Accept(AudioVisitor visitor)

 

{

  visitor.VisitWAV();

 }

}

public

 

abstract

 

class VedioMedia,IMedia

{

 

public

 

abstract

 

void Accept(VedioVisitor visitor);

}

public

 

class RM:VedioMedia

{

 

public

 

override

 

void Accept(VedioVisitor visitor)

 

{

  visitor.VisitRM();

 }

}

public

 

class MPEG:VedioMedia

{

 

public

 

override

 

void Accept(VedioVisitor visitor)

 

{

  visitor.VisitMPEG();

 }

}

請注意,在我的Visitor方法中,并沒(méi)有將節點(diǎn)或元素對象傳遞給Visitor。這一點(diǎn),與通常的Visitor模式實(shí)現小有區別。

下面是Visitor的實(shí)現:

public

 

abstract

 

class AudioVisitor

{

 

public

 

abstract

 

void VisitMP3();

 

public

 

abstract

 

void VisitWAV();

}

public

 

class PlayAudioVisitor:AudioVisitor

{

 

public

 

override

 

void VisitMP3()

 

{

  //實(shí)現MP3的Play方法;

 }

 

public

 

override

 

void VisitWAV()

 

{

  //實(shí)現WAV的Play方法;

 }

}

public

 

class ShowScriptAudioVisitor:AudioVisitor

{

 

public

 

override

 

void VisitMP3()

 

{

  //實(shí)現MP3的ShowScript方法;

 }

 

public

 

override

 

void VisitWAV()

 

{

  //實(shí)現WAV的ShowScript方法;

 }

}

public

 

abstract

 

class VedioVisitor

{

 

public

 

abstract

 

void VisitRM();

 

public

 

abstract

 

void VisitMPEG();

}

public

 

class PlayVedioVisitor:VedioVisitor

{

 

public

 

override

 

void VisitRM()

 

{

  //實(shí)現RM的Play方法;

 }

 

public

 

override

 

void VisitMPEG()

 

{

  //實(shí)現MPEG的Play方法;

 }

}

public

 

class ResizeVedioVisitor:VedioVisitor

{

 

public

 

override

 

void VisitRM()

 

{

  //實(shí)現RM的ShowScript方法;

 }

 

public

 

override

 

void VisitMPEG()

 

{

  //實(shí)現MPEG的ShowScript方法;

 }

}

現在我解釋一下為什么不在Visitor方法中傳遞節點(diǎn)對象。從上面的Visitor實(shí)現,可以看到。每個(gè)Visitor的Visit方法,實(shí)際上代表的就是各自的行為,或者是Play,或者是Resize,等等。而這些行為均是在Visitor中實(shí)現的,而非它訪(fǎng)問(wèn)的節點(diǎn)對象。也就是說(shuō),通過(guò)Visitor模式,我將各個(gè)媒體對象的行為都交給Visitor了。既然干活的對象發(fā)生了轉移,那么發(fā)生了什么責任,也就去找Visitor吧,這個(gè)責任可與媒體對象本身沒(méi)有關(guān)系了啊。

根據Visitor模式,一般還應該提供結構對象(ObjectStructure)角色。然而我在開(kāi)篇名義之處,就提到本例中,媒體類(lèi)型對象是不存在聚合關(guān)系的,因此不需要勞煩ObjectStructure來(lái)枚舉每個(gè)節點(diǎn)了。也許,這個(gè)Visitor模式有些不倫不類(lèi)吧,沒(méi)關(guān)系,我們只需要了解這個(gè)模式的思想。

現在看看客戶(hù)端的調用:

public

 

class Client

{

 

public

 

static

 

void Main()

 

{

  //調用視頻媒體的Play方法;

  VedioMedia rm =

 

new RM();

  rm.Accept(new PlayVedioVisitor());

  //調用音頻媒體的ShowScript方法;

  AudioMedia mp3 =

 

new MP3();

  mp3.Accept(new ShowScriptAudioVisitor());  

 }

}

從上面的Visitor實(shí)現可以看到,每個(gè)Visitor的Visit方法,實(shí)際上代表的就是各自的行為,或者是Play,或者是Resize,等等。而這些行為均是在Visitor中實(shí)現的,而非它訪(fǎng)問(wèn)的節點(diǎn)對象。也就是說(shuō),通過(guò)Visitor模式,我將各個(gè)媒體對象的行為都交給Visitor了。既然干活的對象發(fā)生了轉移,那么發(fā)生了什么責任,也就去找Visitor吧,這個(gè)責任可與媒體對象本身沒(méi)有關(guān)系了哦。

如果要添加行為,那么同樣把責任交給Visitor吧。為該行為定義一個(gè)Visitor類(lèi),繼承抽象Visitor類(lèi)即可??纯幢辉L(fǎng)問(wèn)對象,因為Visit方法接受的是抽象Visitor類(lèi)對象,Accept()方法對于各種行為是完全一致的,你自然不需要修改媒體對象區間的這些所有對象了。這也是Visitor模式最有價(jià)值的體現。例如,我想為視頻媒體增加一個(gè)行為Brighten(),該行為能夠讓畫(huà)面更亮。

首先定義一個(gè)Brighten的Visitor類(lèi):

public

 

class BrightenVedioVisitor:VedioVistor

{

 

public

 

void VisitRM(RM rm)

 

{

  //增加亮度的方法實(shí)現;

 }

 

 

public

 

void VisitMPEG(MPEG mpeg)

 

{

  //增加亮度的方法實(shí)現;

 }

}

我們來(lái)看看,不改變視頻媒體類(lèi)的任何代碼,能否調用Brighten方法?對了,很簡(jiǎn)單:

rm.Accept(new BrightenVedioVisitor());

看了上面的描述,也許你會(huì )認為Visitor模式不僅是可行的,而且真的很可愛(ài)呢。但我卻要說(shuō)它是不可愛(ài)的,至少針對本例是如此。請設想這樣幾種情形:

1、 假設你需要增加新的一種媒體文件,如WMV文件,在既有Visitor模式的架構下,應該怎樣?你頭疼了,因為實(shí)在是太麻煩。你需要定義一個(gè)WAV類(lèi),繼承VedioMedia。最麻煩的是你必須修改VedioVisitor及其所有子類(lèi),因為Visit方法中沒(méi)有包含訪(fǎng)問(wèn)WAV對象的行為。

2、 當各種的對象的行為越來(lái)越多時(shí),怎么辦?你需要為每種行為都創(chuàng )建一個(gè)Visitor。例如我希望提供加亮的同時(shí),還能提供變暗的功能,是不是又要為其建立Visitor對象呢?假如這些行為所屬的Visitor對象之間,又沒(méi)有什么聚合的關(guān)系,即無(wú)法引入ObjectStructure來(lái)管理,你一定會(huì )煩不勝煩的。

3、 當各種對象行為的外部接口非常復雜時(shí),例如傳遞復雜的對象,甚至可能會(huì )有out或ref參數,同時(shí)還有返回對象,又該怎么辦?你一定注意到了,所有的Visit方法所代表的行為都沒(méi)有返回值,也沒(méi)有傳遞參數。如果真要解決,你恐怕只有為被訪(fǎng)問(wèn)對象引入屬性了。這不又要修改被訪(fǎng)問(wèn)對象嗎?

明白它的不可愛(ài)之處了吧。那么Vistor模式的優(yōu)勢又在哪里呢?上面其實(shí)已經(jīng)不厭其煩地說(shuō)過(guò)多次,那就是在保證被訪(fǎng)問(wèn)對象相對穩定的情況下,為現有系統添加行為帶來(lái)了便宜。

尤其我要說(shuō),對于媒體播放器,Vistor模式非但不可愛(ài),而且丑陋。從現實(shí)角度考慮,我們要做一個(gè)媒體播放器,在設計之初,對于各種媒體應具備的行為,通常能夠充分考慮到。且各種媒體的行為是大致相同的。然而對于媒體文件類(lèi)型,反而是無(wú)法估量的。說(shuō)不定,什么時(shí)候又會(huì )出現新成果來(lái)。從mp3到mp4,再到mpn,你能預知嗎?所以,根據本例而言,你是在利用Visitor的劣勢了。

為什么還要寫(xiě)本文?是因為我想告訴你兩點(diǎn):

1、 Visitor模式的優(yōu)勢與劣勢;

2、 通過(guò)一個(gè)反面教材,有時(shí)候比正面教材給人印象更深;

讓Visitor模式用到它最擅長(cháng)的地方吧。讓它不僅可行,而且還要可愛(ài)!

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Java進(jìn)階篇設計模式之十 - 訪(fǎng)問(wèn)者模式和中介者模式
C#設計模式學(xué)習筆記:(21)訪(fǎng)問(wèn)者模式
23種設計模式詳解(五)
設計模式-行為型-訪(fǎng)問(wèn)者模式
訪(fǎng)問(wèn)者模式(Visitor Pattern)
設計模式學(xué)習筆記(九)——Composite組合模式
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久