接口和抽象类的区别知道了,但实际应用中,到底如何选择呢?
其区别:
1:一个类可以实现任意多的接口,但是最多只能对一个抽象类进行子类化。
2:一个抽象类可以包括非抽象方法,而一个接口的所有方法在效果上都是抽象的。
3:一个抽象类可以申明并使用变量,而一个接口不行。
4:一个抽象类中的方法的访问修饰符可以使public,internal,protected,protected internal,private,而接口成员的访问修饰符在默认情况下都是public,而且,在申明接口成员时,不允许使用访问修饰符(甚至不能使用public)。
5:一个抽象类可以定义构造函数,而一个接口不行。
其区别:
1:一个类可以实现任意多的接口,但是最多只能对一个抽象类进行子类化。
2:一个抽象类可以包括非抽象方法,而一个接口的所有方法在效果上都是抽象的。
3:一个抽象类可以申明并使用变量,而一个接口不行。
4:一个抽象类中的方法的访问修饰符可以使public,internal,protected,protected internal,private,而接口成员的访问修饰符在默认情况下都是public,而且,在申明接口成员时,不允许使用访问修饰符(甚至不能使用public)。
5:一个抽象类可以定义构造函数,而一个接口不行。
接口是规范,约定。
抽象类没有完全描述对象信息。
来看下例子。
需求,需要分析简历包括(中文,英文),给出伪代码
public class ChineseResume
{
public ChineseResume(){}
public ResumeDocument Parse(string text,string model)
{
ChineseRegex regex=new ChineseRegex();
ModelInfo modelInfo=regex.GetModelInfo(model);
TextDocument txt=new TextDocument(modelInfo);
TextInfo textInfo=txt.Parse();
if(textInfo!=null)
return new ResumeDocument(textInfo);
return new NothingResumeDocument();
}
}public class EnglishResume
{
public EnglishResume(){}
public ResumeDocument Parse(string text,string model)
{
EnglishRegex regex=new EnglishRegex();
ModelInfo modelInfo=regex.GetModelInfo(model);
TextDocument txt=new TextDocument(modelInfo);
TextInfo textInfo=txt.Parse();
if(textInfo!=null)
return new ResumeDocument(textInfo);
return new NothingResumeDocument();
}
}从对象角度分析,中文简历也好,英文简历也好都是简历,在运行时我不需要知道是中文还是英文,是简历就给我分析吧,很显然这两个类有大量的重复代码,应该抽象了。
public abstract Resume
{
public ResumeDocument Parse()
{
ModelInfo modelInfo=GetModelInfo();
TextDocument txt=new TextDocument(modelInfo);
TextInfo textInfo=txt.Parse();
if(textInfo!=null)
return new ResumeDocument(textInfo);
return new NothingResumeDocument();
} public abstract ModelInfo GetModelInfo();
}public class ChineseResume:Resume
{
private ChineseRegex regex=new ChineseRegex()
public ChineseResume(){}
public override ModelInfo GetModelInfo()
{
return regex.GetModelInfo();
}
}英文简历也是一样。假设我们有个插件平台,我需要将做好的对象加载到此平台中,但平台中中文和英文有很大不现体现时,接口显然很有用。
public class ChineseResume:Resume,IAddin,IResource
{
private ChineseRegex regex=new ChineseRegex()
public ChineseResume(){}
public override ModelInfo GetModelInfo()
{
return regex.GetModelInfo();
} //..实现IAddin接口(平台加载和管理时需要)
//..实现IResource接口(平台对你要的资源进行管理,如文件,数据等等)
}
英文我不需要管理资源(假设没有资源)
public class EnglishResume:Resume,IAddin
{
private EnglishRegex regex=new EnglishRegex()
public EnglishResume(){}
public override ModelInfo GetModelInfo()
{
return regex.GetModelInfo();
} //..实现IAddin接口(平台加载和管理时需要)
}
在这里可以看出接口规范的重要性,它不影响类原有的功能,轻松对别人开放的API进行扩展。
对于regex也可以抽象,加入其它语言扩展也很方便。
认真思考,多做实践,可以去看看理论了。
所以这个问题没有一定的回答,只有经验。
http://community.csdn.net/Expert/topic/5522/5522427.xml?temp=.8039667
抽象类A和继承类B的关系....B is a A;
========================================
playcity(city):请你学会尊重人,每个人都有自己关注的方向,不代表不会你的问题,就是白混
假设有这样一个需求
1、需要封装数据库操作,在操作数据库时,可以根据数据库类型选择使用相应的驱动程序(ODBC、OLEDB、SqlServer、Oracle),分别对应ADO.NET 里的System.Data下的4种Client类。
2、假设需要的数据库操作功能已定(Select()、Delete()、Update())。
3、他们之间有个共同点,就是都需要数据库连接字符串。原先想的是在基类里定义(Select()、Delete()、Update())三个抽象方法,在构造时加上数据库连接字符窜,然后在继承类里边分别实现,这样就对外部隐藏了细节了。
但后来一想,用接口也一样啊,实现接口的类的构造也可以增加一个数据库连接字符窜的参数。就这样我就开始迷糊了
string this[int index] { get ; set ; }
event EventHandler Even ;
void Find(int value) ;
string Point { get ; set ; }
}
public delegate void EventHandler(object sender, Event e) ; 上面例子中的接口包含一个索引this、一个事件Even、一个方法Find和一个属性Point。
函有抽象方法的类为抽象类
抽象方法一般带有abstract关键字
{
void Open();
void Close();
}public abstract class Door
{
void Open(){};
void Close(){};
}就目前来说, 你用Interface还是用abstract class基本上没什么区别, 两者都用来描述Door的行为, 只不过用Interface是在强调Door额外的有Open和Close这两个功能, 而用abstract class则是在强调Door自带有Open和Close的能力走远一点, 假如又有一天, 你要写一个AlarmDoor的类, 这个时候...public interface AlarmDoor
{
void open();
void close();
void alarm();
}public abstract class AlarmDoor
{
void open(){};
void close(){};
void alarm(){};
}现在, 你应该想清楚你究竟是想设计一个报警器还是想设计一扇门, 如果选择Interface, 那你是在想设计一个报警器, 如果选择abstract class, 那你是在想设计一扇门, 说到现在, 是否有点眉目了?C#里面不允许多个父类, 但却允许多个接口, 接口无非是让某个类拥有某种行为, 而抽象类却是在让某个类拥有某种本质, 因此, 我们设计的类, 应该用一个抽象类把它的所有本质都抽象出来, 而它的一些行为(或者说是契约)则通过Interface来实现, 这也能说明为什么C#会不允许多层父类却允许多层接口
从语法定义层面看abstract class和interface 在语法层面,Java语言对于abstract class和interface给出了不同的定义方式,下面以定义一个名为Demo的抽象类为例来说明这种不同。 使用abstract class的方式定义Demo抽象类的方式如下: abstract class Demo {
abstract void method1();
abstract void method2();
…
} 使用interface的方式定义Demo抽象类的方式如下: interface Demo {
void method1();
void method2();
…
} 在abstract class方式中,Demo可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface方式的实现中,Demo只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在interface中一般不定义数据成员),所有的成员方法都是abstract的。从某种意义上说,interface是一种特殊形式的abstract class。 从编程的角度来看,abstract class和interface都可以用来实现'design by contract'的思想。但是在具体的使用上面还是有一些区别的。 首先,abstract class在Java语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。也许,这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。 其次,在abstract class的定义中,我们可以赋予方法的默认行为。但是在interface的定义中,方法却不能拥有默认行为,为了绕过这个限制,必须使用委托,但是这会 增加一些复杂性,有时会造成很大的麻烦。 在抽象类中不能定义默认行为还存在另一个比较严重的问题,那就是可能会造成维护上的麻烦。因为如果后来想修改类的界面(一般通过abstract class或者interface来表示)以适应新的情况(比如,添加新的方法或者给已用的方法中添加新的参数)时,就会非常的麻烦,可能要花费很多的时间(对于派生类很多的情况,尤为如此)。但是如果界面是通过abstract class来实现的,那么可能就只需要修改定义在abstract class中的默认行为就可以了。 同样,如果不能在抽象类中定义默认行为,就会导致同样的方法实现出现在该抽象类的每一个派生类中,违反了'one rule,one place'原则,造成代码重复,同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心。
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();
}
那么具有报警功能的AlarmDoor的定义方式如下: class AlarmDoor extends Door {
void open() { … }
void close() { … }
void alarm() { … }
}
或者 class AlarmDoor implements 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在Java语言中表示一种继承关系,而继承关系在本质上是'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是Java语言中的两种定义抽象类的方式,它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理,因为它们表现了概念间的不同的关系(虽然都能够实现需求的功能)。这其实也是语言的一种的惯用法,希望读者朋友能够细细体会。