Interface And Abstract Class

来源:互联网 发布:炫酷网站首页源码 编辑:程序博客网 时间:2024/05/02 01:11

      李建忠老师在畅谈"C#设计模式纵横谈"时,总是不忘记给我们传输一种思想:让你的代码动起来,去应对变化,也就是让自己的代码在无形中加入时间轴这个概念,在随着时间推移(客户需求变化),你可以神清气爽的让你软件去应对这样的变化而不是抱怨需求变化去憎恨客户的苛刻.这也是设计模式的魅力所在吧,也是设计模式的精髓吧-------哪里有变化就把它隔离出来,封装之.让你的设计优美起来.

      在我们的设计中我们要去分析发现哪些是相对稳定的部分,哪些是相对变化的部分,用设计模式去封装变化的部分.结合到代码实现这个层次上,如何去封装这些变化点呢?当然那,对于不同的场景,是有不同策略来应对的.面向对象这种就思想粉墨登场了,可以说面向对象思想在软件变化过程中体现出来了她的优美,我们就是利用面向对象的机制来设计出这些模式来应对不同的变化.所以我们要在品尝设计模式前一定要有个扎实的面向对象的基础.

     以上我罗嗦了这么多就是要引出面向对象中的重要概念:接口和抽象类.我觉得好多设计模式都是利用这两个锐器耍出来的.下面就就谈谈我对接口和抽象类的理解.

    (一)对接口和抽象类的基本理解.

      接口定义的是一个契约,在C#中,接口中只能包含四种实体:方法,属性,事件,索引器.不能包含常数,构造器,解析器.仔细想下便知道, 接口只是表达了我有什么样的功能,而具体的实现它并不关心,如何实现这些功能是有实现给接口的类来负责的,而常数是不能说明接口有什么样的功能的,因此它存在于接口之中也是没有任何意义的.接口实质上是个抽象体, 它是不能直接new 出来的,所以在接口中就不应该有构造器和解析器.接口中的方法都是抽象方法,也即只有方法头,没有方法体,方法的访问属性默认是public,接口中的方法不能为static而且实现该接口的类对应于接口中的方法也不能为static,原因很简单:只有非静态方法才可能具备多态性,接口既然把实现它所定义的方法交给了实现接口的类,那么接口中的方法就应该为public且为抽象方法.

     抽象类中至少有一个抽象方法,它可以有自己的数据成员和具体方法,也就是说抽象类可以完全实现,但更常见的是部分实现或者根本不实现,从而封装继承类的通用功能.从一个抽象类到多个具体类的继承关系中,共同的代码应当尽量移动到抽象类里,而数据的移动方向是从抽象类到具体类。一个对象的数据不论是否使用都会占用资源,因此数据应当尽量放到具体类或者等级结构的低端。

   实现接口的类必须实现接口中所有的方法,不管它是否需要(有点专横的味道).而继承抽象的类可以选择自己感兴趣的抽象方法来实现.

    接口和抽象类实质上都是抽象体,也可以说接口是抽象类的一种特例.他们不能通过new直接来创建的.

 (二)对接口和抽象类的深层理解.

    1.接口和实现该接口的类没有耦合关系,而抽象类和继承该抽象类的类之间具有很强的耦合关系.

      接口只是表达了我有什么样的功能而不实现他们,而实现这个接口的类才去实现这些功能.因此,接口和实现该接口的类具有一种"like - a "的关系.也就是说实现接口的类有接口的具体功能.实现接口的类like a 接口.接口和实现该接口的类之间没有层次关系.接口具有不变性,也即是,一旦接口被定义和接受就不要去改变它,以保护为使用该接口而编写的应用程序.因此我们在表达一种抽象体时常选择接口.

      抽象类和继承该抽象类的类之间具有继承关系,也就是说有一种"is -a "的关系,具体较强的耦合关系,比如说,苹果是一种水果.这种强耦合关系,导致,抽象类有所改动时,继承该抽象类的类都要牵动.所以选择抽象类时一定要满足"is -a "关系时才去考虑使用它.

     2.我们为什么要使用接口和抽象类,不用他们,代码不可以很好运行吗?

        不用接口和抽象类,你的代码也许现在可以很好的允许甚至高效的运行,但是对于需求的变化你的代码运行的就会很累,更糟糕的是修改代码的你会更累.

        复用性是软件设计的关键,抽象类和接口表达的是一种抽象概念,所谓抽象,我的理解就是稳定,正是他的稳定才提高了软件的复用性.使用接口和抽象类可以使你代码具有灵活性,以不变应万变.所以我们在设计代码时,当一个类关联另外一个类时,我们最好关联的不是一个具体的类,而是针对一个接口或抽象类,那么任何实现这个接口的类或继承该抽象类的类就都可以满足要求。这样就可以动态地将这个关联从一个具体类转换到另一个具体类,而这样做的唯一条件是它们都实现了某个接口或都是从某个抽象类继承来的.

        我们在设计代码时,对于类中方法的参数一般设置为抽象类或接口,这样一来就为对象间的方法调用带来了灵活性,也即是任何实现了这个接口或抽象类的具体类都可以被当前对象调用;而当前对象到底调用的是哪一个具体类的实例则完全可以动态地决定。

  另外,接口使可插入性变得可能。在一个类等级结构中的任何一类都可以实现一个接口,这个接口会影响到此类的所有子类,但是不会影响到此类的任何超类。此类将不得不实现这个接口所规定的方法,而其子类则可以从此类自动继承到这些方法,当然也可以选择置换掉所有的这些方法,或其中的某一些方法。这时候,这些子类就具有了可插入性.

       抽象类和接口有这么多的好处,我们为什么不使用呢,所以我们要适时的使用抽象类和接口,他们会给你的代码带来灵气.

      3.是选择抽象类还是接口?

         上面提到了接口的不变性,所以我们可以说接口是一种绝对的抽象,它是抽象类的一个特例.所以我认为接口才是软件复用的关键,所以说能使用接口的决不考虑使用抽象类.过多的使用抽象类会使你代码耦合性加大.

           也许这个说法有点武断,那么我们就从更深层来分析吧.

          要理解接口和抽象类的选择原则,有两个概念很重要:对象的行为和对象的实现。如果一个实体可以有多种实现方式,则在设计实体行为的描述方式时,应当达到这样一个目标:在使用实体的时候,无需详细了解实体行为的实现方式。也就是说,要把对象的行为和对象的实现分离开来。既然Java的接口和抽象类都可以定义不提供具体实现的方法,在分离对象的行为和对象的实现时,抽象类和接口都可以来实现,选择哪个呢?

          抽象类体现了一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is a"关系,即父类和派生类在概念本质上应该是相同的。对于接口来说则不然,并不要求接口的实现者和接口定义在概念本质上是一致的,仅仅是实现了接口定义的契约而已.

        因此,在接口和抽象类的选择上,必须遵守这样一个原则:行为模型应该总是通过接口而不是抽象类定义.在使用接口的同时仍旧可以使用抽象类,不过这时抽象类的作用是实现行为,而不是定义行为。只要实现行为的类遵从接口定义,即使它改变了父抽象类,也不用改变其它代码与之交互的方式。特别是对于公用的实现代码,抽象类有它的优点。抽象类能够保证实现的层次关系,避免代码重复。然而,即使在使用抽象类的场合,也不要忽视通过接口定义行为模型的原则。从实践的角度来看,如果依赖于抽象类来定义行为,往往导致过于复杂的继承关系,而通过接口定义行为能够更有效地分离行为与实现,为代码的维护和修改带来方便.

(三)接口和抽象类结合使用.

 

           
           
 

 

原创粉丝点击