日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

面向对象理论(6)-Interface Programming-[A]

發布時間:2025/4/16 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 面向对象理论(6)-Interface Programming-[A] 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
面向接口編程(A)
前面的章節對于本篇來說,只是基礎和鋪墊,而且講的很簡單,因為那些很容易理解。我們從這個章節開始,用大量的代碼的配合,來闡述面向接口編程。

接口的演化形式
現在我們回顧一下繼承相關的知識。我們現在給出一組新的繼承體系。它們是和圖形相關的,我們可以假設這樣的一種需求,就是我們要實現一個畫圖板(例如Windows的畫圖板),至少要能在上面繪制幾個圓形和矩形。于是,我們很自然底定義了如下的classes。 class?Shape??? //abstract in fact
{
????
public?virtual?void?draw();
}

class?Circle?:?Shape
{
????
public?override?void?draw()
????{
????????
/*?draw?a?circle?on?some?device?*/
????}
}

class?Rect?:?Shape
{
????
public?override?void?draw()
????{
????????
/*?draw?a?Rect?on?some?device?*/
????}
}
首先要說的是,我們確實是無法給出Shape類的方法draw()的實現。因為它是一個抽象的類型(不要和語言中的抽象類或abstract關鍵字混淆,但是它們確實有莫大的聯系,但是我所謂的抽象是一種真實的抽象),我們不知道一個所謂的“圖形”應該如何被畫出來。這就像你讓我畫一個圖形出來一樣,我感到很為難。我畫個圓圈或者是多邊形,五角星,似乎都不是一個具有抽象意義的圖形。

我們再回顧一下多態,下面的代碼更好的詮釋了多態的作用。
Array<Shape>?shapes?=?{?new?Circle(),?new?Rect(),?new?Circle(),?new?Circle(),?new?Rect()?};

void?drawShapes()
{
??? foreach(Shape?shape?in?shapes)
??? {
??????? shape.draw();
??? }
}
這是一段偽碼,但是很自然地表現除了多態的從容,foreach從容器中循環枚舉出Shape類的各種不同的派生類對象,它們都多態性地調用了它們各自類型的draw()方法。而這個過程又絕沒有很明顯的顯露出某一個具體的派生類的類型的參與。于是,我們還可以很自然地再派生出圓角矩形,或者是五角星,都讓它們繼承自Shape類即可,它們也可以很自然地被放進shapes容器中,而且又不會修改循環處的分毫代碼,這就是我們所追求的可擴展性和“新增代碼不會影響已有的代碼”。

嗯,這一切都很完美,不是嘛? 然而,這真的很完美嘛?

表格(Table)是一個Shape(對象)嘛?文本(Text)是一個Shape嘛?如果我們要有若干個圖層(Layer),每一個圖層是一個Shape嘛?如果是,這些出現在畫圖板上的元素,它們很好的詮釋了is-a的信念嘛?

沒有,因為一個Table不是一個Shape,Text也不是Shape,但是它們也都可以被畫在上面,于是我們需要進行一次重要的演化。

我們在C++的語法教材中不強調接口的概念,而是用純抽象類來表達這一個含義,但是我更愿意用Java的interface關鍵字作為表達。但是我們要清楚,無論是接口,還是基類,抽象基類,多態性都是存在于這樣的語法關系中的。

interface?IDraw?{
????
void?draw();
}

class?Circle?implements?IDraw?{
????
void?draw()?{
????????
/*?draw?a?circle?on?some?device?*/
????}
}

class?Rect?implements?IDraw?{
????
void?draw() {
????????
/*?draw?a?Rect?on?some?device?*/
????}
}
這次演化,似乎是沒有本質改變的,特別是對于C++的編譯器來說,編譯出來的代碼都可能沒有絲毫的不同。也許很多人開始嘆氣了,認為這種形式上的變化根本是無所謂的,甚至就是在浪費時間。
但是我想說的是,對于設計來說,這種變化是本質的變化。因為對象的關系變化了,之前,我們說一個Circle對象也是一個Shape,它滿足is-a的經典關系,但是現在,這種關系被打破了。

Can-do & Constraint
我們在前面的章節中,已經提到了has-a和is-a的對象關系了,現在,我們的重點是can-do的關系,這種關系表示約束(Constraint)。
于是,在上面的代碼中,我們說Circle類實現了IDraw接口,或者說Circle對象能夠完成IDraw接口所要求的行為。
void?draw(IDraw?d)
{
????d.draw();
}

而這個函數就更直觀地表達出約束的概念了,“畫可畫之對象”,準確地說,這個函數更直接地完成 IDraw接口的約束語義表達:只有實現了約束的對象才可以被傳入,并調用其draw()方法(注意,而并不是有draw()方法的對象都可以被傳入和調用,相關問題可以對比C++09的concept)。

Array<IDraw>?drawList?=?{?new?Circle(),?new?Rect(),?new?Circle(),?new?Table(),?new?Rect(),?new?TextArea()?};

void?draw()
{
????
foreach(IDraw?d?in?drawList?)
????{
????????d.draw();
????}
}
我用這段偽碼,明確地表示了這樣的一個新情況,Circle被畫到畫圖板中去了,Table和TextArea也可以被畫到上面去了。

依然是存有懷疑,難道Table派生自Shape就有問題嘛?難道一定要弄出一個IDraw,讓它看起來有道理才是合理的?
不是的。首先,如果IDraw接口沒有取代Shape類,我們也要承認這樣幾個事情,Shape類還是帶著IDraw接口的含義,盡管我們不把它抽象出來。

而且,設計沒有對錯之分,是不是適應需求才是最實際的評判標準。我們當前的例子還很簡單,我們只涉及到了元素的繪制(draw),但是也許還有其他的問題 (新需求總是很多的),比如ALPHA混合,圖層的遮擋,元素的選擇,螞蟻線的繪制,等等。例如,當我們選擇了一個Rect的時候,他的四周有螞蟻線,而我們選擇了一個TextAread的時候,它的四周是帶有8個調節點的邊框。可是,我們不打算讓螞蟻線和邊框參與其他元素的遮擋計算和ALPHA混合計算,而且它們也不參與序列化,于是,它們既不是Shape,也不應該實現IDraw接口。經驗告訴我們,Shape類是不足以成為所有元素的基類的,IDraw接口也不是萬能的。具體的解決方案要看需求,如何應對這些需求,我們會在后面的內容中有所涉及。





轉載于:https://www.cnblogs.com/healerkx/articles/1233252.html

總結

以上是生活随笔為你收集整理的面向对象理论(6)-Interface Programming-[A]的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。