架构:也成为软件体系结构,用来指可以预制和可重构的软件框架结构。
架构模式:表示了软件系统的基本结构化组织纲要。是开发一个软件系统的基本设计决策。
设计模式:提供了一个用于细化软件系统的子系统或组件,或他们直接的关系的纲要。规模上比框架模式小,单又独立于特定的编程语言和编程范型。
惯用法:对应于一种编程语言的低层模式。
架构是高层设计,着眼与不同业务中共性的解决方案,而模式是通用原理。模式用来指导架构设计,同时架构设计选择模式。
组合是一种聚合,其组合的对象直接具有较强的所以关系约束和一致的生存周期约束。一个组合而成的新对象完全拥有对其组成部分的支配权,包括他们的创建和销毁等,即组合而成的新对象对组成部分的内存分配,内存释放有绝对的责任。
合成不同于继承,他表示了整体与部分的关系,即一个组成部分。继承则是表示派生类是基类的一个特殊种类。
继承的缺点:
1.继承复用破坏封装,继承将基类的实现细节暴露给派生类。
2.如果基类的实现发生改变,那么派生类的实现也不得不发生改变。
3.从基类继承而来的实现是静态的,只能在编译期做出改变。
把继承关系重构为合成关系,将系统对变化的适应力从静态提升到动态,提高了设计的灵活性和代码的复用性。
优先使用对象合成,而不是类继承。
方法绑定:建立方法调用和方法本体之间的关联。
多态:虚方法调用使你可以对不同类中的同名方法有不同的实现,并在运行期进行动态绑定。
多态产生的条件:
1.基类定义了一个或者多个虚方法。
2.一个或多个派生类覆盖那些虚方法。
3.一个实例变量(或参数),其类型使基类,但实际上它引用的是某个派生类的一个实例。
抽象方法必须首先是虚方法或者是动态方法。
适合作为类层次架构顶层基类的不应该是一个具体类,而应该是一个抽象类。
使用抽象类的原则:
1.抽象类应当拥有尽可能多的共同代码。
2.抽象类应当拥有尽可能少的数据。
一个类实现一个接口,这种关系叫做接口继承;而一个类是另一个类的派生类,这种关系叫做实现继承。
DelPhi中一个类最多只能有一个基类,但是可以同时实现多个接口。
可以把接口看作是动态绑定函数调用抽象基类的一种替代方法。
接口和类的最重要区别是,接口仅仅描述方法的特征,而不给出方法的实现;而类不仅给出方法的特征,
而且给出方法的实现。
1. 面向接口编程利用OO的一个基本性质——多态,相同方法不同表现。可以这样想一下,client编写自己程序的时候,如果直接面向一个具体类写程序,那这个程序有个风吹草动的,那client就要受到影响,但如果面向一个接口就不同了,某个具体类变了,只知接口,不知具体类的client就可以完全不动。 都说上层领导比较好当,因为可以干的事通常对老百姓来说是虚的,越虚就越不容易错。
这个道理在OO中也是适用的。
2. 换个视角看,面向接口编程反映OO的另一个方面——封装,接口将具体实现封装了起来,可以不影响客户的情况下切换实现
3. 接口的作用,一言以蔽之,就是标志类的类别(type of class)。把不同类型的类归于不同的接口,可以更好的管理他们。OO的精髓,我以为,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如c++、java、c#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。(cowboy的名言是“抽象就是抽去像的部分”,看似调侃,实乃至理)。
[b]空接口的使用
在接口使用的时候,空接口有2种情况:
1.类似于ObjectBuilder中的IBuilderPolicy,他们往往是做一个标记,表示需要某个功能.当然你也可以这么用,来表示你的类具有某个功能,实现了你的某个接口.
namespace Microsoft.Practices.ObjectBuilder
{
///
/// Represents a builder policy interface. Since there are no fixed requirements
/// for policies, it acts as a marker interface from which to derive all other
/// policy interfaces.
///
public interface IBuilderPolicy
{
}
}[/b]
[b]
2.你的接口继承了别的接口(非空),你的接口本身没有声明函数.这种情况一般是你不希望用户使用父接口作为参数类型,因为他们的用途可能不同,此时就可以用空接口来实现.
interface Text
{
string getText();
}
interface SqlText : Text
{
}
可以看到,Text接口是用于返回一个字符串.而SqlText是一个空接口,它继承了Text接口.也就是说SqlText也是一种Text.但是我们可以知道,任何一个字符串不一定是Sql字符串,所以此时声明了一个SqlText接口来用于表名当前的字符串是一个Sql字符串.你的函数可以这样声明:
public void doQuery(SqlText sqlText)
而不是这样:
public void doQuery(Text text)
避免用户产生歧义的想法,一眼看去,就明白应该传入一个Sql字符串.
接口的成员为什么没有委托
我们都知道C#的接口是可以包含事件的,其实当我们看到事件的时候,很容易就会想到委托,委托是事件的基础,如果对委托和事件不是特别清楚的程序员就一定不会明白,为什么C#接口中可以包含事件而不能有委托呢。其实简单的说法就是委托也是类型,delegate关键字引入的是一个新的类型,所以一个C#接口无法包容一个委托并把它当作成员;而event关键字引入的是一个新的成员,因此事件可以归人接口。理解这点,我们要从C#接口的使命说起,C#接口是一个契约,规范了接口实现者的行为,而不是要有些什么。很简单,例如“党员”是个接口,它肯定有个动作是“为人民服务”,“某某党员”实现了“党员”这个接口,那么“某某党员”肯定也要“为人民服务”,至于你“某某党员”是否必须拥用“电脑”、“小孩”。那么“党员”这个接口中肯定不会有规定。这也就是接口的目的,规范了实现者的一些行为。所以C#接口的成员都是方法,不会有其它了。稍有c#常识的程序员都明白,c#中的属性,其实就是两个方法,一个Set方法,一个Get方法,同样事件和索引器也都是方法,请看下面的接口:
public interface IDrawingObject
{
event EventHandler OnDraw;
string Name
{
get;
set;
}
int this[int index]
{
get;
set;
}
void SetValue();
}
该接口包含了c#接口所能接纳的所有成员,事件,属性,索引器,方法。把该接口编译后,我们用MSIL Disassembler工具查看一下:
这下大家都明白了,其实属性Name对应于Get_Name(),Set_Name()这两个方法,事件OnDraw对应于add_OnDraw(),remove_OnDraw()这两个方法,索引器对应于get_Item(),set_Item()这两个方法。在看下面的委托和类的定义:
public delegate void TestEventDelegate(object sender, System.EventArgs e);
class TestClass
{
public void SetValue()
{ }
}
抽象类:一种不能实例化而必须从中继承的类,抽象类可以提供实现,也可以不提供实现
子类只能从一个抽象类继承
抽象类应主要用于关系密切的对象
如果要设计大的功能单元,则使用抽象类。
如果预计要创建组件的多个版本,则创建抽象类
接口:是完全抽象的成员集合,不提供认识实现。
类或者结构可以继承几个接口。
接口最适合为不相关的类提供通用功能
如果要设计小而简练的功能块,则使用接口
接口一旦创建就不能更改。如果需要接口的新版本,必须创建一个全新的接口
如果没有特殊声明,所有的对象方法都是静态的.。静态方法的工作方式正如一般的过程和函数调用。在编译时,编译器决定方法地址,并与方法联接。
静态方法的基本好处是派送相当快。因为由编译器决定方法的临时地址,并直接与方法相联。虚方法和动态方法则相反,用间接的方法在运行时查找方法的地址,这将花较长的时间。
调用虚方法与调用任何其它方法一样,但派送机制有所不同。虚方法支持在后代对象中重定义方法,但调用方法完全相同,虚方法的地址不是在编译时决定,而是在运行时才查找方法的地址。
为声明一个新的方法,在方法声明后增加virtual指令。方法声明中的virtual指令在对象虚拟方法表(VMT)中创建一个入口,该虚拟方法表保存对象类所有虚有拟方法的地址
当你从已有对象获得新的对象,新对象得到自己的VMT,它包含所有的祖先对象的VMT入口,再增加在新对象中声明的虚拟方法。后代对象能覆盖任何继承的虚拟方法。