首页 > 其他 > 详细

基类 的薄弱之处

时间:2015-11-17 16:39:34      阅读:245      评论:0      收藏:0      [点我收藏+]

这个问题怎么解释呢,比如说:程序总是由人来设计与编写的,所以工作开始时考虑不到某些问题当然也是很正常的事,所以可能在工作进行了一段时间后发现基类需要变更。

你想, 如果我在基类中更改了成员的数据类型,以及那些允许重写的那些方法和属性, 那派生类及其子类还能正常工作吗?尤其是当一个团队中的多个开发人员一起来创作基类和派生类时,就更是要命了。

很多情况下,大家可能已经把基类和一些派生类编译成二进制形式进行提交了。更改基类,重新编译再分布,会牵一发而 动全身,导致项目的崩溃。

所以我们把这叫做‘脆弱的基类’。也就是说像蛋壳一样不堪一击喽。它是整个工程中最薄弱最致命的环节。

如果对项目的前期设计考虑尽可能周详,在工程实施中对项目的代码控制与相关性分析做得踏实,会起到很好的效果。但是不管一个人如何努力,有时还是无法避免对基类进行不可预见的更改。

所谓成事在人呀,经过程序员们的摸索,有了一些处理的手段,不过并不是什么完美解决方案,只能在某种程度上减轻危害。

我们常用的一个方法,最直接的思想就是,把有可能发生的更改,全都放在派生类中进行,不在基类中做。

这具体是什么意思呢?

我们在基类中使用的是抽象类,它内含的方法与属性只有定义,没有进行实现,而把实现部分都放在派生类中做。

这样一来,抽象类自身是无法被实例化的。但是它的好处不言而喻, 就是有可能发生实现上的更改,都会只涉及到它的派生类了。VB.NET中就提供了这样的手段。

来看一小段代码:

Module Module1
    MustInherit 关键字此类只能作为基类使用,并且不能直接在里面创建实例.
    Public MustInherit Class BaseClass
        MustOverride 关键字表示此属性或过程未在类中实现,且在实现之前须在派生类中重写可
        Public MustOverride Sub OutputA(ByVal x As Long)
        Public MustOverride Function GetValue(ByVal x As Integer) As Long

    End Class

    Public Class DerivedClass
        Inherits BaseClass
        Dim strA As Char
        Public Overrides Function GetValue(x As Integer) As Long
            Dim i As Long = x * Asc(strA)
            Return i
        End Function

        Public Overrides Sub OutputA(ByVal x As Long)
            strA = Chr(x + 10)
        End Sub
    End Class


    Sub Main()
        Dim MyClassA As New DerivedClass
        MyClassA.OutputA(10) 实例化派生类后,使用重写基类的方法 InputA
        Console.WriteLine("访问派生中重写的基类函数 GetValue 后得到的值为: {0}", MyClassA.GetValue(100))
        Console.Read()
    End Sub

End Module

 

这里要注意两个问题:

一个是关键字,我们用 MustInherit 来修饰类名,使类成为抽象类,在它的成员中,把方法和属性前加入 MustOverride 修饰符表示它们必须在派生类中加以实现。

第二个要注意的是,派生类必须对所有用 MustOverride 标识的基类方法和属性都进行实现,只重写了 OutputA,不写 GetValue 编译器会报错的。

大家可能已经发现了,这的确可以解决一部分问题,但好象只能解决在基类中进行实现的代码有更改的问题,对于数据类型的的更改好象没有什么效果!!

所以我刚才说,是在某种程度上,但解决基类中数据类型的更改,道并不麻烦,我们可以在派生类中用 Shadows 来解决呀!但如果基类要做功能扩展,怎么办呢?

如果是要做扩展,最安全的方法是添加新成员,而不是对基类的大肆修改。

一般是往派生类添加设计时缺失的新成员。最好不要使用 Overloads 关键字来命名与基类相同的成员,那样往往会带给你意想不到的问题。最好重新定义新成员,命名上也要尽量与基类已有的成员名区分开来。其实,也可以往抽象类基类中添加新成员的定义,但这样一来,需要为基类制定版本,虽然不会对应用程序造成毁灭性的危害,但是应该要能够完全地控制与管理自己的代码。

我们一般是不希望扩展基类的。

意思是指基类的脆弱问题实际上是客观存在的,我们所做的就是要最大程度的减小这个问题带来的危害?

没错,对于一个应用程序的设计者来讲,想使用面向对象方法来开发,必须要在设计的时候精心 策划类的层次结构。一般来说,是有这样几个准则需要把握的:

第一,遵循先通用,再专用的原则。

      先设计好层次结构中每一级别的类中的通用部分,也就是提供给派生类继承的成员和标识为 Public 的成员;

第二,在定义数据类型和存储区域时要有预留量,以避免以后更改困难。

      例如,即使当前数据可能仅需要 Integer 类型就够了,在设计时我们使用 Long 类型的变量。当然,最好能物尽其用,也不要盲目放大;

第三,在一个项目中,必须统一管理与分配团队中使用的所有的命名,以减少命名冲突。

       这一点其实事关重大;

第四, 要使用提供可行的最低访问权限的访问修饰符声明类成员。

       内部类成员应声明为 Private;仅在类内与派生类中才需要的成员应标记为 Protected;外部访问类的数据成员可以标记为 Friend ,但仅限于该模块是定义该类的项目的一个组成部分;使用 Public 标识的成员,只能是实例化时真正需要的内容,而且经常用在类层次结构的底部,也就是说,一个规范的操作,标准的命名体系可以决定基类的强壮与否。

不难想象,后续的种种措施,就是决定是给脆弱的基类穿上多厚的防护衣,因为基类始终都是薄弱的 。

我们要在工程实践中不断地学习与磨练,了解更多的知识,获得 更多的经验,这样才会成长为一名合格的程序设计师。就拿继承来说吧,在.NET 中其实支持三种继承方式:实现继承、接口继承、可视继承。我们其实只用了第一种继承方式!

基类 的薄弱之处

原文:http://www.cnblogs.com/lfls128/p/4971871.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!