面向对象编程概念、要点介绍

Day 1

Day2 继承

What:是复用代码,复用概念的一种技术。
【代码复用的一种方式】
Why:为了复用代码,复用概念,方便管理多个类【层次,树】
Who、where,when:只要用C#写代码,就在使用【无意识】
【有意识:刻意用 :父类】
没有明确指定父类,默认父类是object
Object是任何类的直接或者间接父类!
一切皆对象【都是object对象类的子类】

为什么需要继承

为了保留原有的功能,
通过继承可以复用,不用每次都从头开始
为了能够对类进行层次性的管理 狗 猫 动物
继承的优点
1. 复用代码的一种方式
2. 统一概念,概念复用 复用概念 动物》狗 语法上
以层次化【树】的方式管理类 动物
——————
| |
狗 猫
继承的缺点
耦合度高:父类的改变直接影响到所有的子类,
而不需要通知子类
建议:
继承层次不要太深,三层即可
尽量选择抽象类来继承
继承的语法
写法:class A: B 表示A类继承B类,
A类称为子类(派生类),
B类称为父类(基类,超类)
继承的特点:
1父类中所定义除私有成员外都继承给子类
【子类拥有父类中所有非私有成员】
2构造方法不继承给子类【公共,私有】
结论:因为继承,调用父类中的方法,有三种调用法

// method 1:
Animal obj= new Animal();
obj.Walk();
// method 2:
Dog obj2 = new Dog();
obj2.Walk();
// method 3:
Animal obj3= new Dog();
obj3.Walk();

Animal
继承中的构造方法 好多结论,考点!
1.知识点不重要,unity中很少写构造方法;》因为创建对象 常见在Start中初始化。 实例化,会拉到GameObject中。

2笔试中爱考【不好记,容易出错!】

  1. 构造方法不会继承给子类,
  2. 但是在创建子类对象时,自动调用父类的构造方法,
    且父类构造方法先执行,子类构造方法后执行.【从子进入,再进入父,执行完父,执行子 结束】
  3. 什么时候调用构造方法:
    new类时=创建对象的时候
    new【1分配内存空间 ->2调用构造方法】
  4. 当子类创建对象时,默认调用父类的无参构造方法, 如果父类没有无参构造方法,则报编译错误。
    解决方法有两个:
    1.为父类添加无参构造方法。
    2.在子类的构造方法中用base关键字指明要调用父类的哪一个有参构造方法
    Public Dog() : base(“ssss”)
    {

}
如果程序员没有明确的写构造方法,编译器或自动生成一个【无参构造方法】
如果程序员明确的写构造方法,编译器就不给生成了。

  1. Q:1.为什么需要构造方法?
    A obj=new A();1创建对象 【1分配内存空间,放对象;2初始化对象字段】 //A:
    只要类型需要创建对象,都需要构造方法, 因为构造方法是创建对象的唯一通道.

  2. Q:2.为什么要重载构造方法?
    A:构造方法在创建对象的同时,并为对象成员做初始化, 通过传递的参数为成员赋值。
    当我们希望得到初始状态不同的对象时,需要使用重载构造方法 。
    **比如:开新班有 unity的班, php的班, web前端的班, .net的班, Mis老师:准备一个教室,开新班!环境!
    7. Q:3.构造方法之间可不可以互相调用 语法上:可以; 实际用途:几乎不用,没意义
    //A:可以,本类构造方法互相调用通过this关键字, 子类调用父类的构造方法通过base关键字


哪种情况适合用继承组织类的关系:
[如果有多个类,概念一致,有很多共性 就可以考虑:继承]。
例如:动物,狗,猫
a.两个或更多个类从概念上是一致的
b. 从数据和行为上是一致的
c.会不会这几个类型统一处理

技巧:哪种情况适合用继承
举例:
[多个类, A B is成立,适合使用继承] 动物,狗
狗是动物,所以狗可以继承动物

Day3 多态

类的继承:
**类成员的横向扩展:**成员越来越多。
**类成员的纵向扩展:**行为改变,版本增高。

抽象类

c#抽象类可以包括有方法体的方法吗?
-不可以 抽象类当中必须是抽象的方法和属性,抽象的方法是不能有具体的方法体的,而且有抽象方法的类 。如果有其他类继承此类的话,那么此类就必须重写父类中的抽象方法。
-抽象类可以包含普通方法 但是抽象类不能被实例化。
总之:
1、抽象类中的抽象属性和抽象方法必须是公有的,因此必须有public修饰符
2、子类必须override抽象类中的所有抽象属性和抽象方法,如果没有全部override,那么子类必须是抽象类
3、抽象类中可以有非抽象属性和非抽象方法,也可以是私有或者公有,但是如果是私有的话子类就不能访问,无意义,所以一般情况下都设置为公有
4、有抽象方法或抽象属性的类一定是抽象类,抽象类中的属性或方法不一定都是抽象的

参考链接:
链接: link.
举例: link.

Timthy.Liu举得例子:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApp2
{
    class AbstractClassTest
    {
        static void Main()
        {
            Vehicle v = new Car();
            v.Run();
            v.Fill();
        }
    }

    abstract class Vehicle
    {
        public void Stop()
        {
            Console.WriteLine("Stopped.");
        }
        public void Fill()
        {
            Console.WriteLine("Fill the gas.");
        }
        public abstract void Run();
        
    }

    class Car:Vehicle
    {
        public override void Run()
        {
            Console.WriteLine("the Car is running.");
        }
    }
    class Truck : Vehicle
    {
        public  override void Run()
        {
            Console.WriteLine("the Truck is running.");
        }
    }
    class RaceCar : Vehicle
    {
        public override void Run()
        {
            Console.WriteLine("the RaceCar is running.");
        }
    }
}

重写(Override)成员方法

“hide方式”在实际项目中经常被视为一种错误。
-实际应用中,“hide方式”的 调用子类型中的方法是要尽量避免的。这种方式没什么意义,所以经常不用。而是用override

using System;

namespace ConsoleApp6
{
    class Program
    {
        static void Main(string[] args)
        {
            Animal animal = new Animal();        
            Dog dog = new Dog();
            dog.Sleep(5);// overload
            dog.jump(); // override
        }
       
    }

     class Animal
    {
        public virtual void jump()
        {
            Console.WriteLine("the animal jumps");
        }
        public void Sleep()
        {
            Console.WriteLine("Animal睡觉");
        }
        public int Sleep(int time)
        {
            Console.WriteLine("Animal {0}点睡觉", time);
            return time;
        }
    }
    class Dog: Animal
    {
        public override void jump()
        {
            Console.WriteLine("the dog jumps");
        }
    }
  
}

输出结果:
/
conclusion:如此可见,main函数中即使用父类Animal 声明的对象,因为实例化的是子类new Dog(),所以jump函数仍然调用子类的 jump功能,而自动把父类的jump给hide掉了。这就是多态。
多态:当用父类对象引用子类实例时,这个父类对象调用的方法永远是子类的方法,而且是继承链上最新版本的方法。

重写(Override)属性

using System;

namespace ConsoleApp6
{
class Program
{
static void Main(string[] args)
{
Animal animal = new Animal();
Dog dog = new Dog();
dog.Sleep(5);
dog.jump();
// test the property speed override
Animal animalDog = new Dog();
animalDog.jump();
Console.WriteLine("the speed is " + animalDog.speed);
}

}

 class Animal
{
    // property  override
    private int _speed ;
    public virtual int speed
    {
        get { return _speed; }
        set { _speed = value; }
    }
    public virtual void jump()
    {
        Console.WriteLine("the animal jumps");
        _speed = 100;
    }
    public void Sleep()
    {
        Console.WriteLine("Animal睡觉");
    }
    public int Sleep(int time)
    {
        Console.WriteLine("Animal {0}点睡觉", time);
        return time;
    }
}
class Dog: Animal
{
    private int rpm;//齿轮转速
    public override int speed 
    { 
        get { return rpm / 100 ; }
        set { rpm = value / 50; } 
     }
    public override void jump()
    {
        Console.WriteLine("the dog jumps");
        rpm = 50000;
    }
}

}

在这里插入图片描述

接口:

一个纯abstract 类,其实就是接口:
TimothyLiu的例子如下:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApp2
{
    class AbstractClassTest
    {
        static void Main()
        {
            Vehicle v = new Car();
            v.Run();
            v.Fill();
        }
    }

    interface  IVehicleBase
    {
      void Stop();
      void Fill();
      void Run();
    }
    abstract class Vehicle:IVehicleBase
    {
        public  void Stop()
        {
            Console.WriteLine("Stopped.");
        }
        public  void Fill()
        {
            Console.WriteLine("Fill the gas.");
        }
        abstract public void Run();        
              
    }

    class Car:Vehicle
    {
        public override void Run()
        {
            Console.WriteLine("the Car is running.");
        }
    }
    class Truck : Vehicle
    {
        public  override void Run()
        {
            Console.WriteLine("the Truck is running.");
        }
    }
    class RaceCar : Vehicle
    {
        public override void Run()
        {
            Console.WriteLine("the RaceCar is running.");
        }
    }
}
//控制台会输出:the Car is running.
//Fill the gas.

接口为了解耦合而生

面向对象的编程的要点之一是高内聚,低耦合。所以引入接口,其目的:
1) 方便测试:代码越多,测试量越大。interface is without codes. 所以不需要测试其功能是否正确。
2) 降低耦合度,因为interface is without codes ,所以其对继承类的功能实现没有影响,降低了父类-子类的耦合度。
2) 功能提供方替代容易。
接口正是为起到了这个作用而诞生。请看如下实例:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApp2
{
    class InterfaceTest2
    {

        static void Main()
        {
            var user = new PhoneUser(new Mi());
            user.UsePhone();
        }          
   
    }
    class PhoneUser
    {
        private IPhone _phone;
        public PhoneUser(IPhone phone)
        {
            _phone = phone;
        }
        public void UsePhone()
        {
            _phone.Dial();
            _phone.Pickup();
            _phone.Send();
            _phone.Read();
        }
    }
    interface IPhone
    {
        void Dial();
        void Pickup();
        void Send();
        void Read();
    }
    class Nokia : IPhone
    {
      public   void Dial()
        {
            Console.WriteLine("Nokia Dial");
        }
        public void Pickup()
        {
            Console.WriteLine("Nokia Pickup");
        }
        public void Send()
        {
            Console.WriteLine("Nokia Send");
        }
        public void Read()
        {
            Console.WriteLine("Nokia Read");
        }
    }
    class Mi : IPhone
    {
        public void Dial()
        {
            Console.WriteLine("Mi Dial");
        }
        public void Pickup()
        {
            Console.WriteLine("Mi Pickup");
        }
        public void Send()
        {
            Console.WriteLine("Mi Send");
        }
        public void Read()
        {
            Console.WriteLine("Mi Read");
        }
    }
}

解读:

  • 低耦合的实现:IPhone(手机)接口定义功能Dial,Pickup,Send,Read 与其派生类Nokia ,Mi 2款具体手机是低耦合的关系。也就是说,在实现Nokia ,Mi 2款具体手机的Dial,Pickup,Send,Read 功能时,并不依赖于IPhone(手机)接口中对于手机功能的任何定义。也就是你怎么改IPhone(手机)接口,对于Nokia ,Mi 2款具体手机的实现功能,是无影响的(低耦合)。
  • 调用端的简化:在PhoneUser调用端,实例化一个具体的手机类 var user = new PhoneUser(new Mi());

依赖反转原则(dependency inversion)

在这里插入图片描述

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApp2
{
    class Interface_DependencyInversion
    {
        static void Main()
        {
            DeskFan deskFan = new DeskFan(new PowerSupply());
            Console.WriteLine(deskFan .Work());
        }
    }
   public  interface IPowerSupply
    {
        int GetPower();
    }
    public class PowerSupply:IPowerSupply //电源
    {
        public int GetPower()
        { return 260; } //这是一个非常不好的设计, 此处赋值(高耦合),未来测试会经常修改,这样会导致应用PowerSupply的其他类被影响。
    }
    public class DeskFan  //台式电扇
    {
        private IPowerSupply _powerSupply; //台式电扇的电源参数。 这是一个紧耦合模式,
            //因为PowerSupply中电压值改变,将导致Deskfan工作状态直接改变。
        public  DeskFan(IPowerSupply powerSupply) //初始化函数给台式电扇一个电源(即电压V)
        {
            _powerSupply= powerSupply;
        }
        public string Work()
        {
            int power = _powerSupply.GetPower();
            if (power <= 0) 
                return "Won't work";
            else if (0 < power && power < 100)
                return "Low Power Work";
            else if (100 <= power&&power <= 220)
                return " Work Fine";
            else 
                return "Warning : too high power";
        }
    }
}

解读:
类PowerSupply和类DeskFan 都继承了接口IPowerSupply

在这里插入图片描述

隐藏

方法隐藏
解决父类的方法在子类不适合的问题。
但是父类的方法不能重写(不是virtual,abstract,override),
此时可能选择方法隐藏,
子类新定义一个方法,与父类方法同签名,
子类型用新定义的方法隐藏掉父类继承的旧方法。
方法隐藏时语法建议在方法前加new关键字
Why:为了选择性的复用【解决父类的方法在子类不适合的问题】
What:隐藏【方法隐藏,方法隐藏技术,隐藏技术】
隐藏是多态的一种实现方式。
【使用步骤:】
在父类中定义普通的方法
在子类中定义隐藏方法
(用new修饰的和父类中的方法名相同参数相同的方法,
new可以省略,最好不省略)

虚方法

什么是虚方法:
定义【语法】:用vritual关键修饰的已经实现的方法,即是虚方法
语义【含义】:虚方法表示一个可以在子类中重写的方法
【重写不重写都可以】
方法重写

  1. 重写【方法重写,方法重写技术,重写技术】
  2. 重写有三种重写的方法
    1》 虚方法重写
    2》 重写方法重写
    3》 抽象方法重写
  3. 为什么需要重写:为了选择性复用(解决父类所
    定义方法在子类中不适用)
  4. 虚方法重写 【定义,使用步骤 】
    是多态实现的一种方式;
    【步骤1:】在父类中定义虚方法
    【步骤2:】在子类中定义重写方法
    【重写方法:和父类中的
    方法名相同参数相同方法返回类型相同,要加override】
    注意对应关系!!
    特点:调父的实现 1种写法;调子的实现 2种写法
    父调子意义重大!

方法重写解决父类所定义方法在子类中不适用(虚方法),或父类没有实现(抽象方法),这样的方法子类可以重写,重写是为了满足子类对该方法的不同需求.
三种方法可以重写 :
a) abstract 方法在子类必须重写,除非子类也是抽象类
b) virtual 方法在子类可以重写,父类方法的做法与子类不同
c) override方法,已经重写过的方法,在子类还可以继续重写,除非被标识为sealed.

方法重写时必须在方法前加override关键字

sealed

封闭类定义:sealed修饰的类
特点:不能被继承。不能有子类。可以实例化!

sealed(密封)的作用 1放在类前 封闭类 2重写方法前 封闭方法

  1. 用在类的定义上,指示当前类不能做父类,也就是任何类都不可继承当前类
  2. 用在重写的成员,指示当前类的子类,不能再次重写该成员
    sealed 用在方法前边,必须和override 在一起
    sealed override 修饰的方法 叫封闭方法,只有重写方法才可以封闭。

动态绑定(晚期绑定)与静态绑定(早期绑定)[了解一下即可]

绑定:类型与关联的方法的调用关系,
通俗讲就是一个类型能够调用哪些方法 B:A A:?
【系统确定一个类型能调用哪些方法的过程,绑定】
1静态绑定(编译时绑定):是指调用关系是在运行之前确定的,即编译期间
2 动态绑定(运行时绑定):是指调用关系是在运行期间【过程中】确定的。
静态绑定因为在编译期确定,不占用运行时间,
所以调用速度比动态绑定要快
动态绑定因为在运行期确定,占用运行时间,但是更灵活。
动态绑定比静态绑定灵活性好. 速度略低
方法隐藏是静态绑定
方法重写是动态绑定
方法隐藏原理 了解
方法隐藏是子类的方法表加入一个新项,新项中表示的方法签名与继承来的方法签名一致,但是在方法表中不能出现相同签名的方法项,所以必须要隐藏掉一个。子类用新项隐藏旧项。方法隐藏是在方法表加新项
方法重写原理 了解
父类的方法在子类重写后,是子类型将方法表中相应方法签名对应的方法所在的地址重写了,重写后,原方法签名项关联到新方法的地址。当引用调用该方法时,访问新地址中的方法。
所以方法重写后,不管是通过父类还是子类型的引用,调用方法时,都调用对象真实类型中定义的方法
如:A是父类,B是子类,A中Show方法在子类中重写
A obj = new B(); //A类型引用指向B类型的对象
obj.Show();
此时调用的是B类型定义的Show方法.

什么时候使用抽象类,什么时候用接口

  1. 项目分析时,对某角色提取的是不同类别的共性,提取的有:特征,行为。其中,有的行为能确定下来;有的行为确定不下来。这种情况适用于抽象类『封装』;
  2. 提取的是不同类别的共性,提取的只有:行为。这些行为确定不下来,适用于接口『封装』

Day5 委托的应用

1. 委托作为参数传给调用函数:

将方法做为参数传递,可以将一个方法的执行代码注入到另一个方法中
方法1(int,string数据数值) Add(int a,int b)
方法2(方法1语句块)
定义 方法2(委托类型 委托对象){ 调用委托;…….}
调用 方法2(委托对象=lambda表达式)
为什么要注入:
1定义算法/方法时 :
有的语句/步骤能定下来,有的暂时定不下来
可以使用委托表示确定不下来的
2调用时再确定 把有些功能推迟到客户端【调用端】确定!

using System;
using System.Collections.Generic;
using System.Text;

namespace DemoDelegate5
{
    class Delegate5
    {
        static void Main()
        {
            int a = 4, b = 2;
            TestDelegateCallFun test = new TestDelegateCallFun();
            Handler handler = test.ToBeCallFun;
            test.CallFun(handler(a, b));// delegate transfer as a agument;

        }
    }
    delegate int Handler(int x, int y);
    class TestDelegateCallFun
    {
       public  int ToBeCallFun(int x, int y)
        {
            return x + y;
        }

       public   void CallFun(int x)
        {
            Console.WriteLine("total =" + x);
        }
    }
   
}

2.实现回调,实现的方式比接口更灵活

  1. 实现回调,实现的方式比接口更灵活
    回调含义 1 方法 系统调用的 【不是程序员直接调用的】
    含义 2 这里的含义
    定义方法 有些定义时确定不下来,留给客户端确定
    调用时候,从 调用端 到定义端
    回到调用端 再到定义端执行 【灵活性】
    回到调用端,结束
    案例2: 回家 做事情【?复习,看电视,玩游戏,聊天】
    方法1 方法2
    唯一,能确定的 不确定的
    进行程序设计,实现代码!
    1》 接口可以作为方法的参数!
    2》 委托可以作为方法的参数!
    3》 有何不同?委托可以实现回调,作为参数,比接口更灵活

事件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值