欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

重温面向对象核心 上

程序员文章站 2022-03-21 21:31:07
实例解读面向对象核心,所有例子基于 C#,涉及我们实务中最常关心的问题: 1、封装、继承、多态; 2、抽象类、接口; 3、委托、事件。 ......

实例解读面向对象核心,所有例子基于 c#,涉及我们实务中最常关心的问题:

1、封装、继承、多态;

2、抽象类、接口;

3、委托、事件。         

一、面向对象三大特性:封装、继承、多态

每个对象都包含它能进行操作的所有信息(不必依赖其他对象),这个特性称为封装

封装降低了耦合,类内部的实现可以*的修改,使类具有清晰的对外接口。

 

对象的继承代表了一种“一般到特殊”的关系,例如 学生(student)是一种人类(person)。

继承定义了类如何相互关联,共享特性。

继承的工作方式是,定义父类和子类,或叫做基类与派生类,上面的例子中,可以让 student(子类)继承 person(父类)。

 

多态:表示不同的对象可以执行相同的动作,但要通过它们自己的实现代码执行。

这个文字理解比较抽象,具体说明见下面示例中讲解:

例子分为 父类,子类,调用 三部分。

先建立个mvc项目oopdemo,我们定义一个父类:抽象的图形类(shape), 子类 :矩形类 (rectangle),在 homecontroller 中 index 方法中调用。

 

父类:

定义一个属性name 和方法 getname, 将该成员声明为虚拟的(virtual, 有方法体),除了字段不能是虚拟的,属性、事件和索引器都可以是虚拟的,通常虚拟的是方法, 子类通过 override来覆写。

    public class shape

    {

        public string name { get; set; }

 

        public shape(string name)

        {

            this.name = name;

        }

 

        public virtual string getname()

        {

            return "父类的图形名: "+ name;

        }

    }

 

子类继承父类:

    public class rectangle:shape

    {

        public rectangle(string name):base(name)

        { }

 

        public override string getname()

        {

            return "子类的图形名: " + name;

        }

 

        public double length { get; set; }

        public double width { get; set; }

        public double getarea()

        {

            double area = length * width;

            return area;

        }

    }

 

子类中关于继承的说明:

1、子类拥有父类非private的属性和功能

      子类拥有父类的 属性name,getname()方法。

      * 构造方法有一些特殊,它不能被继承,只能被调用(使用 base)。

        public rectangle(string name):base(name)

        { }

 

2、子类具有自己的属性和功能,即子类可以扩展父类没有的属性和功能。

      矩形有自己的 长、宽属性,及计算面积的 getarea 方法。

        public double length { get; set; }

        public double width { get; set; }

        public double getarea()

        {

            double area = length * width;

            return area;

        }

 

3、子类可以以自己的方式实现父类的功能(方法重写)

     通过override重写

        public override string getname()

        {

            return "子类的图形名: " + name;

        }

 

 

调用

在homecontroller的index方法中获取名字。

        public iactionresult index()

        {

            shape rec1 = new rectangle("正方形");

            viewbag.name = rec1.getname();

            return view();

        }

 

前端通过viewbag获取name

 重温面向对象核心 上

 

 

调用时关于多态的说明

1、子类以父类身份出现

      注意是以 shape(父类) 而不是 rectangle(子类) 来声明的,然后用 rectangle(子类)来实例化。(对象的声明是父类,而不是子类,实例化的对象是子类)

           

 shape rec1 = new rectangle("正方形");

 

 

2、子类在工作时以自己的方式来实现(覆写父类方法)

        public override string getname()

        {

            return "子类的图形名: " + name;

        }

 

当方法被调用时,都只有位于对象继承链最末端的方法会被调用。也就是说,虚方法是按照运行时类型而非编译时类型进行动态绑定调用的。

 

3、子类以父类身份出现时,子类特有的属性和方法不可使用

这些都是不能用的:

        public double length { get; set; }

        public double width { get; set; }

        public double getarea()

        {

            double area = length * width;

            return area;

        }

 

例如 rec1.getarea() ,这个是获取不到的。

 

二、抽象类与接口

抽象类

回顾下我们的例子。

shape实际上不会实例化,它只是抽象出一些共同的东西用来继承。

抽象类通常代表一个抽象概念,它提供一个继承的出发点,当设计一个新的抽象类时,一定是用来继承的,所以,在一个以继承关系形成的等级结构里面,树叶节点应当是具体类,而树枝节点应该是抽象类。也就是说,具体类不是用来继承的。

考虑把没有任何意义的父类改成抽象类,让抽象类拥有尽可能多的共同代码,拥有尽可能少的数据。

 

我们来修改一下例子。

将父类做如下方框处更改,其他的都不变。

 重温面向对象核心 上

 

我们将shape改成了抽象类, public abstract class shape {…}

将getname删除了方法体,改成了抽象方法 public abstract string getname();

说明:

1、抽象类不能实例化

2、抽象方法是必须被子类重写的方法(可以看成是没有实现体的虚方法)

3、如果类中包含抽象方法,那么类就必须被定义为抽象类,不论是否还包含其他一般方法。

 

接口

声明接口的语法与声明抽象类完全相同,但不允许提供接口中任何成员的执行方法。

实现接口的类就必须实现接口中所有的方法和属性。

我们来定义一个接口:

    /// <summary>

    /// 定义各种各样的面积算法

    /// </summary>

    public interface ical

    {

        string getareaalgorithm();

    }

  

在rectangle中继承这个接口,并实现接口的方法

    public class rectangle:shape, ical

    {

 

        // 此处省略其他代码xx行...

        // 实现接口 ical 中的方法

        public string getareaalgorithm()

        {

            return "矩形的面积算法:长 × 宽";

        }

}

 

修改调用方法:

        public iactionresult index()

        {

            shape rec1 = new rectangle("正方形");

            viewbag.name = rec1.getname();

 

            ical cal=  new rectangle("正方形2");

            viewbag.cal = cal.getareaalgorithm();

 

            return view();

        }

 

显示结果:

 重温面向对象核心 上

 

三、总结:

1、类是对对象的抽象;抽象类是对类的抽象;接口是对行为的抽象

2、如果行为跨越不同对象,可使用接口

3、从设计角度看,抽象类是从子类中发现公共的东西,泛化出父类,而接口根本不知道子类的存在,方法如何实现还不确认,预先定义。

 

抽象类往往都是通过重构得来的,抽象类是自底向上抽象出来的,而接口是自顶向下设计出来的。

 

祝学习进步 :)

重温面向对象核心 上