`
webcode
  • 浏览: 5947117 次
  • 性别: 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:
这里我还想谈谈关于构造函数的继承,子类的构造函数在默认的情况下会继承父类的无参构造函数,这一点一定要注意。
分享到:
评论

相关推荐

    类的继承与代码的复用

    {实验报告需单独下载,不过源代码里有注释} ...总结:先建立一个抽象类shape,然后建立一个核心类求体积(面积*高),再建立各种实例图形(对抽象类的继承),直接可输出图形体积,即实现了代码的复用。

    es5生成class支持构造传参继承函数复用多继承

    es5 生成class,支持构造传参、继承、函数复用、多继承;

    Python语言基础:类的继承.pptx

    在继承关系中,已有的、设计好的类称为父类、基类或超类,自定义的新类称为子类或派生类。派生类可以继承父类的公有成员,但是不能继承其私有成员。类继承的语法为 class 类名(被继承类类名)。 实例:使用类的继承性...

    C++:通过私有(private)继承复用类实现工厂函数详解

    C++:通过私有(private)继承复用类实现工厂函数详解。

    PHP Trait代码复用类与多继承实现方法详解

    众所周知,一直以来PHP和很多语言一样是单继承的语言,但是常常在编码过程中,我们需要在当前类中使用两个或两个以上的其他类的方法,这种情况下继承就不能实现,而往往采用new方式实例化很多要用到的类,这样就会很...

    软频率复用技术研究及其在LTE系统中的应用

    软频率复用(Soft Frequency Reuse,SFR)继承了部分频率复用的优点,同时采用动态的频率复用因子,比较显著的提高了频率利用率

    Java面向对象继承.pdf

    在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。 implements关键字 使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,...

    继承窗体的设计C#源码

    继承窗体的设计C#源码

    类和对象、对象和封装、继承、多态、异常等教学...

    Java面向对象内容的详细讲解,适合初学者学习,有七章节面向对象文档内容。

    Java 接口与继承

    继承是一种由已有类创建新类的机制,是面向对象程序设计的基石之一 创建子类的语法 class SubClass extends SuperClass{ ...(2) 继承是存在于面向对象程序中的两个类之间的一种关系 (3) 通过继承实现代码复用

    设计模式:可复用面向对象软件的基础--详细书签版

    它将成为我在寻找面向对象设计思想过程中经常翻阅的一本书﹕这正是复用的真实含义所在,不是吗﹖”--sanjiv gossain, journal of object-oriented programming [/font] 目 录 序言 前言 读者指南 第1章 引言 1 ...

    D10继承,抽象类.zip_java继承_抽象类

    继承是面向对象的三大特征之一....实现继承的类被称为子类. 被继承的类被称为父类. 父类和子类的关系, 是一种一般和特殊的关系. 例如水果和苹果的关系, 苹果继承了水果, 苹果是水果的子类, 水果是苹果的父类.

    ODOO12图书项目其它模型继承机制.mp4

    前面我们介绍了模型的基本继承,在官方文档中称为经典继承。这是最常用的继承方式,最容易想到的就是in-place继承。获取模型并对其继承。添加的新功能会自动添加到已有模型中,而不会创建新模型。 可以为_inherit ...

    面向对象编程:Python类与继承深度解析

    面向对象编程:Python类与继承深度解析 描述: 该资源深入讲解Python中的面向对象编程(OOP)原则,包括类的定义、继承、多态和封装等概念,适合希望提升代码组织和复用能力的开发者。

    c++第八章 继承与多态课件ppt

    该机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构。体现了由简单到复杂的认识...

    简单谈谈javascript代码复用模式

    在javascript中,并没有类的概念,所以代码的复用,也并不局限于类式继承。javascript中创建对象的方法很多,有构造函数,可以使用new创建对象,并且可以动态的修改对象。javascript的非类式继承(可称为现代继承...

    彻底搞懂python继承

    在继承关系中,已有的、设计好的类称为父类或基类,新设计的类称为子类或派生类。派生类可以继承父类的公有成员,但是不能继承其私有成员。如果需要在派生类中调用基类的方法,可以使用内置函数super()或者通过...

    C++继承PPT

    C++语言继承详细阐述,继承使软件复用变得简单、易行,可以通过继承复用已有的程序资源,缩短软件开发的周期。本文档主要介绍继承的方式,要注意在继承方式下派生类与基类对象之间的关系,以及派生类构造函数如何...

Global site tag (gtag.js) - Google Analytics