当前位置: 移动技术网 > IT编程>软件设计>面向对象 > 重温面向对象核心 上

重温面向对象核心 上

2019年08月06日  | 移动技术网IT编程  | 我要评论

实例解读面向对象核心,所有例子基于 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、从设计角度看,抽象类是从子类中发现公共的东西,泛化出父类,而接口根本不知道子类的存在,方法如何实现还不确认,预先定义。

 

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

 

祝学习进步 :)

 

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网