原文地址:http://dev.firnow.com/course/4_webprogram/asp.net/netjs/2007118/85034.html
abstract class和interface是C#語言中對于抽象類定義進行支持的兩種機制,正是由于這兩種機制的存在,才賦予了C#強大的面向對象能力。abstract class和interface之間在對于抽象類定義的支持方面具有很大的相似性,甚至可以相互替換,因此很多開發者在進行抽象類定義時對于abstract class和interface的選擇顯得比較隨意。
其實,兩者之間還是有很大的區別的,對于它們的選擇甚至反映出對于問題領域本質的理解、對于設計意圖的理解是否正確、合理。本文將對它們之間的區別進行一番剖析,試圖給開發者提供一個在二者之間進行選擇的依據。
下面我們主要從設計理念層面看看abstract class和interface的區別!
abstarct class在C#語言中體現了一種繼承關系,要想使得繼承關系合理,父類和派生類之間必須存在"is a"關系,即父類和派生類在概念本質上應該是相同的。對于interface 來說則不然,并不要求interface的實現者和interface定義在概念本質上是一致的,僅僅是實現了interface定義的契約而已。為了使論述便于理解,下面將通過一個簡單的實例進行說明。
考慮這樣一個例子,假設在我們的問題領域中有一個關于Door的抽象概念,該Door具有執行兩個動作open和close,此時我們可以通過abstract class或者interface來定義一個表示該抽象概念的類型,定義方式分別如下所示:
使用abstract class方式定義Door:
abstract class Door {
abstract void open();
abstract void close();
}
使用interface方式定義Door:
interface Door {
void open();
void close();
}
其他具體的Door類型可以extends使用abstract class方式定義的Door或者implements使用interface方式定義的Door。看起來好像使用abstract class和interface沒有大的區別。
如果現在要求Door還要具有報警的功能。我們該如何設計針對該例子的類結構呢(在本例中,主要是為了展示abstract class和interface反映在設計理念上的區別,其他方面無關的問題都做了簡化或者忽略)下面將羅列出可能的解決方案,并從設計理念層面對這些不同的方案進行分析。
解決方案一:
簡單的在Door的定義中增加一個alarm方法,如下:
abstract class Door {
abstract void open();
abstract void close();
abstract void alarm();
}
或者
interface Door {
void open();
void close();
void alarm();
}
class AlarmDoor :Door {
void open() { … }
void close() { … }
void alarm() { … }
}
或者
class AlarmDoor :Door {
void open() { … }
void close() { … }
void alarm() { … }
}
這種方法違反了面向對象設計中的一個核心原則ISP(Interface Segregation Priciple),在Door的定義中把Door概念本身固有的行為方法和另外一個概念"報警器"的行為方法混在了一起。這樣引起的一個問題是那些僅僅依賴于Door這個概念的模塊會因為"報警器"這個概念的改變(比如:修改alarm方法的參數)而改變,反之依然。
解決方案二:
既然open、close和alarm屬于兩個不同的概念,根據ISP原則應該把它們分別定義在代表這兩個概念的抽象類中。定義方式有:這兩個概念都使用abstract class方式定義;兩個概念都使用interface方式定義;一個概念使用abstract class方式定義,另一個概念使用interface方式定義。
顯然,由于Java語言不支持多重繼承,所以兩個概念都使用abstract class方式定義是不可行的。后面兩種方式都是可行的,但是對于它們的選擇卻反映出對于問題領域中的概念本質的理解、對于設計意圖的反映是否正確、合理。我們一一來分析、說明。
如果兩個概念都使用interface方式來定義,那么就反映出兩個問題:
1、我們可能沒有理解清楚問題領域,AlarmDoor在概念本質上到底是Door還是報警器?
2、如果我們對于問題領域的理解沒有問題,比如:我們通過對于問題領域的分析發現AlarmDoor在概念本質上和Door是一致的,那么我們在實現時就沒有能夠正確的揭示我們的設計意圖,因為在這兩個概念的定義上(均使用interface方式定義)反映不出上述含義。
如果我們對于問題領域的理解是:AlarmDoor在概念本質上是Door,同時它有具有報警的功能。我們該如何來設計、實現來明確的反映出我們的意思呢?前面已經說過,abstract class在C#語言中表示一種繼承關系,而繼承關系在本質上是"is a"關系。所以對于Door這個概念,我們應該使用abstarct class方式來定義。另外,AlarmDoor又具有報警功能,說明它又能夠完成報警概念中定義的行為,所以報警概念可以通過interface方式定義。如下所示:
abstract class Door {
abstract void open();
abstract void close();
}
interface Alarm {
void alarm();
}
class AlarmDoor extends Door implements Alarm {
void open() { … }
void close() { … }
void alarm() { … }
}
這種實現方式基本上能夠明確的反映出我們對于問題領域的理解,正確的揭示我們的設計意圖。其實abstract class表示的是"is a"關系,interface表示的是"like a"關系,大家在選擇時可以作為一個依據,當然這是建立在對問題領域的理解上的,比如:如果我們認為AlarmDoor在概念本質上是報警器,同時又具有Door的功能,那么上述的定義方式就要反過來了。
abstract class和interface是C#語言中的兩種定義抽象類的方式,它們之間有很大的相似性。但是對于它們的選擇卻又往往反映出對于問題領域中的概念本質的理解、對于設計意圖的反映是否正確、合理,因為它們表現了概念間的不同的關系(雖然都能夠實現需求的功能)。這其實也是語言的一種的慣用法,希望讀者朋友能夠細細體會。
原文地址:http://www.cnblogs.com/yangbin990/archive/2005/09/13/236235.html
參考:Abstract and Sealed Classes and Class Members (C# Programming Guide).
public abstract class A
{
// Class members here.
}
abstract :必須被繼承.
public abstract class A
{
public abstract void DoWork(int i);
}
abstract class 里也可包含abstract 方法, 但方法就沒有{}, 因為abstract 方法不可以有內容. 繼承abstract class 的class 內部必須定義那些abstract 方法, 給他真正的含義.
// compile with: /target:library
public class D
{
public virtual void DoWork(int i)
{
// Original implementation.
}
}
public abstract class E : D
{
public abstract override void DoWork(int i);
}
public class F : E
{
public override void DoWork(int i)
{
// New implementation.
}
}
virtual:兒子類看不到的方法, 也就是說不想讓兒子看到的方法.
public sealed class D
{
// Class members here.
}
sealed:sealed class 不可以做base class,也就是說不可以被繼承.當然也不可以和abstract 同時出現, 因為正好互相抵觸.
原文地址:http://www.cnblogs.com/3stones/archive/2007/03/22/684694.html
c#中的interface abstract 與 virtual
2007-02-13 10:42
interface用來聲明接口 1.只提供一些方法規約,不提供方法主體. 如: public interface IPerson { void getName();//不包含方法主體 } 2.方法不能用public abstract等修飾,無字段變量,無構造函數。 3.方法可包含參數。 如 public interface IPerson { void getAge(string s); }
一個例子(例1): public interface IPerson { IPerson(); //錯誤 string name; //錯誤 public void getIDcard();//錯誤
void getName(); //right void getAge(string s); //right }
實現interface的類 1.與繼承類的格式一致,如 public class Chinese:IPerson{} 2.必須實現 interface 中的各個方法
例2,繼承例1 public class Chinese:IPerson { public Chinese(){} //添加構造 public void getName(){} //實現getName() public void getAge(string s){} //實現getAge() }
abstract聲明抽象類、抽象方法 1.抽象方法所在類必須為抽象類 2.抽象類不能直接實例化,必須由其派生類實現。 3.抽象方法不包含方法主體,必須由派生類以override方式實現此方法,這點跟interface中的方法類似
如 public abstract class Book { public Book() { }
public abstract void getPrice(); //抽象方法,不含主體 public virtual void getName() //虛方法,可覆蓋 { Console.WriteLine("this is a test:virtual getName()"); } public virtual void getContent() //虛方法,可覆蓋 { Console.WriteLine("this is a test:virtual getContent()"); } public void getDate() //一般方法,若在派生類中重寫,須使用new關鍵字 { Console.WriteLine("this is a test: void getDate()"); } }
public class JavaBook:Book { public override void getPrice() //實現抽象方法,必須實現 { Console.WriteLine("this is a test:JavaBook override abstract getPrice()"); } public override void getName() //覆蓋原方法,不是必須的 { Console.WriteLine("this is a test:JavaBook override virtual getName()"); } }
測試如下: public class test { public test() { JavaBook jbook=new JavaBook(); jbook.getPrice(); //將調用JavaBook中getPrice() jbook.getName(); //將調用JavaBook中getName() jbook.getContent(); //將調用Book中getContent() jbook.getDate(); //將調用Book中getDate()
} public static void Main() {
test t=new test(); } }
virtual標記方法為虛方法 1.可在派生類中以override覆蓋此方法 2.不覆蓋也可由對象調用 3.無此標記的方法(也無其他標記),重寫時需用new隱藏原方法
abstract 與virtual : 方法重寫時都使用 override 關鍵字 interface中的方法和abstract方法都要求實現
原文地址:http://www.cnblogs.com/Dlonghow/archive/2008/07/26/1251974.html
最近在忙于Silverlight 上打印功能的實現,采用Report Definition Language(RDL) (一種 SQL Server 基于報表定義規范)。大體情況是:項目中一種原有的數據格式需要轉換成一種通用的數據格式,由它來生成生成各種類型的文檔(PDF、BMP等)。
在定義框架的控件類時,真正對internal 訪問修飾符有了較深的認識和使用,特總結如下,供參考:
1. internal 關鍵字是類型和類型成員的訪問修飾符。內部成員只有在同一程序集中的文件內才是可訪問的。有關程序集的更多信息,請參見組件和程序集。
2. 內部訪問通常用于基于組件的開發,因為它使一組組件能夠以私有方式進行合作,而不必向應用程序代碼的其余部分公開。
例如,用于生成圖形用戶界面的框架可以提供“控件”類和“窗體”類,這些類通過使用具有內部訪問能力的成員進行合作。由于這些成員是內部的,它們不向正在使用框架的代碼公開。
在定義具有內部訪問能力的成員的程序集外部,引用該成員是錯誤的
警告 盡管不能用 C# 重寫 internal virtual 方法,但可以用某些語言(如使用 Ilasm.exe 的文本 Microsoft 中間語言 (MSIL) 重寫它。有關 internal 和其他訪問修飾符的比較請參見 可訪問性級別。
|
posted on 2010-08-22 23:21
漂漂 閱讀(395)
評論(0) 編輯 收藏 引用 所屬分類:
c#開發