`
isiqi
  • 浏览: 16480890 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

类在继承中的复用[转载]

阅读更多
类在继承中的复用
面向对象编程的一个重要特征就是类的继承,通过 类的继承,子类可以获得
父类定义的公有功能特性。但 是实现复用的方法却有多种,通常利用类的继承来实现
功能复用的方法有三种:
直接继承父类的方法实现复用;
调用父类的方法构成自己的方法实现复用;
通过抽象方法来实现逻辑关系的复用;
这三种方法的根本原理是一致的,也就是利用类对象存在公有特性的特征,第1
2 种方法是抽象出公有的功能特性,而第3 种要更高级一些,它是抽象出公
有的逻辑关系特性。我们在实现和利用复用的时候,不管采用那种方法,都应该
遵循一个原则,叫做类的封闭性原则,这个原则有两个方面的含义:
完备性: 一个类要完成一个独立的业务过程,该类的内部应该定义了这个业务
的整个过程,尽量不要在这个类定义了一些过程,而在另一个类中又定义了另外
一些过程。
透明性: 一个类要提供一项功能给其他的类复用,该项功能对其使用者是透
明的,不但在实现上是透明的,而且在使用上也应是透明的。
前2种方式都比较简单,这边针对的种方式给个不错的例子
通过抽象方法来实现逻辑关系的复用能够较好地遵循类的封闭性原则。对车辆这个类做分析,可以发现任何车辆要行驶,都是由驱动带动轮子进行滚动向前行驶的,因此驱动带动轮子向前行驶是所有车辆公有的逻辑关系,因此比较好的方式是类在继承中能够继承这种共有的逻辑关系,而不是简单的轮子滚动的功能。这样我们可以定义一个车辆的抽象类,在车辆抽象类中定义了车辆行驶的方法,但是不同类型的车辆的行驶是不一样的(2轮或4轮回N轮驱动==),所以我们可以定义了两个方法,一个是公有的轮子滚动的方法,它实现了所有车辆的轮子滚动功能,另一个是驱动的抽象方法,它在车辆抽象类并不实现,因为抽象的车辆并不知道是哪种驱动。而在行驶方法中,先调驱动方法,然后调用滚动方法,这样就实现了前面所说的车辆行驶的逻辑关系。
代码如下:
public class abstract Vechile
{
private void Roll
{
/ / 实现滚动功能
......
}
/ /
抽象的驱动方法
protected abstract void Drive();
/ / 车辆的行驶逻辑方法
public void Go()
{
// 驱动
Drive();
// 滚动
Roll();
}
}
这样,在它的子类当中,就直接继承了行驶的方法,
但是在子类中必须实现驱动的方法,下面是汽车子类的定义:
public class Car extends Vechile
{
//
实现父类的抽象的驱动方法
public void Drive()
{
// 具体特有的驱动功能代码
.......
}
}
这样在汽车子类中,只需要关心它自己驱动功能的实现,而车辆是如何行驶,轮子是如何滚动都在车辆父
类中定义好了的,子类继承了这种逻辑关系,在子类中在这种复用方法当中,车辆行驶的业务全过程是在
车辆类中进行了完整的定义,要使用父类的公有功能轮子滚动方法对于子类是完全透明,在子类当中根本不会
出现对滚动方法的调用,轮子滚动的方法已经是父类的私有方法了。
如何调用这些功能呢?车辆类是一个抽象类,
是不能实例化,实际当中也是这样,并不存在一台抽象的车。但是我们在行驶车辆时,其实关注的是它的行驶功能,
因此我们可通过抽象的车辆类来调用具体子类车辆实例
Vechile vechiletest = new Car();
{
/ / 调用车辆行驶功能
vechiletest.Go;
.....
}
在调用过程中我们可以发现,使用抽象的父类定义了类变量,创建的的确是子类的实例,后面都是通过父
类的类变量进行调用。这样做有一个好处,如果车辆类型要改变了,只要把创建的实例改一下,不会影响后面
的调用代码。
在使用者的眼中,只有车辆类,具体如何行驶是由背后的具体实例来完成,这一点对于使用者是
透明的。
顺便分析一下功能的执行过程,首先调用父类的行驶方法,在父类行驶方法的执行中,发现驱动方法
是抽象方法,就会寻找该抽象方法的实现,这样就调用了子类驱动的实现方法,之后,再调用父类的轮子滚动
方法。这样就完成了整个行驶过程的调用。对于调用者来说,只有车辆的行驶方法。就好比坐着车子行驶,不
必知道车子是如何驱动的,轮子是如何滚动。
Arty:
面向对象中,我们一般通过对象的继承和合成来实现复用.
合成关系分为聚合关系和组合关系.聚合是整体/部分关系的抽象(has-a关系).组合关系是一种包含关系("contains-a"关系)部分和整体的生命周期是一样的.一个组合而成的新对象完全拥有对其组成部分的支配权,包括它们的创建和销毁等.
通过合成实现的复用,新对象的存取组成对象的唯一方法是通过组成对象的接口;有利于封装,因为新对象看不到组成对象的内部细节;依赖较少,不像继承中,派生类得依赖基类;这种复用可以在运行期内动态进行,新对象可以动态地引用与组成对象类型相同地对象.不过,这种复用造成系统需要管理的对象较多的局面.
我们在开发时应该优先考虑合成复用,而不是继承复用.
Timmy:
.Net中还有一个比较好用的关键字virtual:

virtual 关键字用于修改方法或属性的声明,在这种情况下,方法或属性被称作虚拟成员。虚拟成员的实现可由派生类中的重写成员更改。
调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。

示例
在该示例中,Dimensions 类包含 x 和 y 两个坐标和 Area() 虚方法。不同的形状类,如 Circle、Cylinder 和 Sphere 继承 Dimensions 类,并为每个图形计算表面积。每个派生类都有各自的 Area() 重写实现。根据与此方法关联的对象,通过调用正确的 Area() 实现,该程序为每个图形计算并显示正确的面积。
// cs_virtual_keyword.cs
// Virtual and override
using System;
class TestClass
{
public class Dimensions
{
public const double pi = Math.PI;
protected double x, y;
public Dimensions()
{
}
public Dimensions (double x, double y)
{
this.x = x;
this.y = y;
}
public virtual double Area()
{
return x*y;
}
}
public class Circle: Dimensions
{
public Circle(double r): base(r, 0)
{
}
public override double Area()
{
return pi * x * x;
}
}
class Sphere: Dimensions
{
public Sphere(double r): base(r, 0)
{
}
public override double Area()
{
return 4 * pi * x * x;
}
}
class Cylinder: Dimensions
{
public Cylinder(double r, double h): base(r, h)
{
}
public override double Area()
{
return 2*pi*x*x + 2*pi*x*y;
}
}
public static void Main()
{
double r = 3.0, h = 5.0;
Dimensions c = new Circle(r);
Dimensions s = new Sphere(r);
Dimensions l = new Cylinder(r, h);
// Display results:
Console.WriteLine("Area of Circle = {0:F2}", c.Area());
Console.WriteLine("Area of Sphere = {0:F2}", s.Area());
Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());
}
}
输出
Area of Circle = 28.27
Area of Sphere = 113.10
Area of Cylinder = 150.80
这个应该也可以算作继承中的复用吧
Justin:
这里我还想谈谈关于构造函数的继承,子类的构造函数在默认的情况下会继承父类的无参构造函数,这一点一定要注意。
分享到:
评论

相关推荐

    c#试题 网络转载 很不错啊!

    继承允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码复用。多态则允许不同的对象对同一消息作出不同的响应。 2. foreach遍历:在C#中,如果要使用foreach循环遍历对象,该对象要么实现了`...

    Java程序员面试的试题集(1_122)帮助初学者的技术问题(转载)

    在Java中,抽象可以通过抽象类和接口来实现,使开发者能够定义类的骨架而不必提供具体实现,从而促进代码的复用和模块化设计。 2. **继承**:继承支持类之间的层次结构,允许创建的新类(子类)继承现有类(父类)...

    C++的学习方法及书籍推荐 (转载).doc

    模板允许在编译时创建针对不同类型的函数和类,实现泛型代码,增强了代码的复用性。编译时类型推导是模板的关键特性,使得程序员可以编写适用于多种类型的代码,而无需显式指定类型。STL(Standard Template Library...

    转载:ActivityGroup 实现TabHost

    ActivityGroup是继承自android.app.Activity的类,它允许你在同一个Activity中嵌套其他的Activity,从而在不同的"tab"之间切换。在旧版Android中,如果你想要在每个Tab下面都有复杂的视图结构,ActivityGroup提供了...

    展现C#世界[转载]

    - C#简化了C++的一些复杂特性,例如移除了宏、模板和多重继承,这些在企业级开发中可能导致问题。 - 指针在C#中不再普遍存在,这增加了代码的安全性,避免了非法内存访问。 - 使用单一的操作符"."替代了C++中的::...

    高质量C++编程指南(转载-中文).pdf

    - **构造函数与析构函数**:理解构造函数的初始化列表、析构函数的清理职责,以及它们在对象生命周期中的作用。 - **拷贝构造函数与赋值函数**:重视拷贝构造函数和赋值函数的实现,确保对象复制和赋值的正确性。 #...

    Eclipse快捷键大全(转载)

    **Ctrl+T:** 显示当前类的继承结构。对于理解类之间的关系非常有用。 **Ctrl+W:** 关闭当前编辑器。这可以帮你快速关闭不再需要的文件。 **Ctrl+K:** 定位到下一个与选中文本相同的部分。这对于查找和替换相似...

    转载面向对象的理解

    ### 面向对象的理解 #### 一、面向过程与面向对象的概念对比 ...总结来说,面向对象编程通过封装、继承和多态等机制,提高了代码的可读性、可维护性和可扩展性,成为现代软件开发中的主流编程范式之一。

    Javascript - 全面理解 caller,callee,call,apply (转载)

    在实际开发中,`call`和`apply`经常用于继承、对象方法复用和函数绑定等场景。例如,当我们想在新的对象上使用现有对象的方法,可以使用`call`或`apply`来实现: ```javascript function Animal(name) { this.name...

    在 PHP 和 Laravel 中使用 Traits的方法

    在传统的单继承语言中,一个类只能继承自一个父类,这限制了代码的复用能力。使用Traits可以像“复制和粘贴”代码一样将方法组合到类中,这使得开发者可以从不同的类中混合和匹配所需的方法,而不用受限于单一的继承...

    【转载】Maven 模块划分

    在软件开发过程中,Maven作为一个强大的项目管理和构建工具,被广泛应用。本文将深入探讨Maven中的模块划分,以及如何有效地组织和管理大型项目。我们将会分析"app-parent"这一特定的压缩包文件名,理解其背后的含义...

    二十三种设计模式【PDF版】

    使用类再生的两个方式:组合(new)和继承(extends),这个已经在 thinking in java中提到过. 设计模式之 Proxy(代理) 以 Jive 为例,剖析代理模式在用户级别授权机制上的应用 设计模式之 Facade(门面?) 可扩展的使用...

    c#学习完全手册,适用于初学者

    继承允许一个类(子类)从另一个类(父类)继承属性和方法,实现代码复用。多态则是子类可以替代父类的地方,提供更具体的实现,增强了程序的灵活性。 5. **接口** 接口定义了一组方法签名,但不包含实现。类可以...

    不明飞行物:互联网转载

    2. **函数与箭头函数**:JavaScript中的函数是第一类对象,可以作为参数传递,也可以作为返回值。箭头函数是ES6引入的简洁语法,简化了函数的定义,但需要注意的是,箭头函数没有自己的this值,而是继承自外层作用域...

    EEE-eee.zip资源包

    3. **面向对象编程**:Python支持面向对象编程,包括类的定义、对象的创建、继承、封装和多态等概念。初学者可以借此了解如何构建和使用面向对象的解决方案。 4. **异常处理**:Python提供了try/except语句来处理...

    Jewel:网上转载的宝石消除源码,cocos2d-x 3.8可以完美运行

    "C++"标签明确了项目的主要编程语言是C++,这意味着源代码将包含大量的C++语法和面向对象编程概念,如类、对象、继承、多态等。同时,由于Cocos2d-x主要是用C++实现的,所以这个标签也表明了项目与Cocos2d-x库的集成...

    how-javascript-works:有关javascript工作原理,事件循环,服务工作者等的知识

    第十五章:类和继承及 Babel 和 TypeScript 代码转换探秘 第十六章:存储引擎及如何选择合适的存储 API 第十七章:Shadow DOM 内部构造及如何构建独立组件 第十八章:WebRTC 及点对点网络通信机制 第十九章:自定义...

Global site tag (gtag.js) - Google Analytics