【C#基础详解】(十五)面向对象 多态

15.1 多态简介

1)多态的概念:

        让一个对象能够表现出多种的状态(类型),意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。

        假设有一个主人类。喂食不同的动物。不同动物对象调用方法的时候,对重复的代码频繁的修改。代码的可展拓展性,可维护性差。所以我们可以用一个Animal类作为参数,让不同的动物继承这个动物类,这就是多态。

2)实现多态的三种手段:

虚方法(virtual-override)

抽象类(abstract)

接口(interface )

3)多态的好处:

        应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。(继承)

        派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。(多态的真正作用)

15.2 多态--虚方法

        在父类的方法前面加关键字virtual, 子类重写该方法时在方法名前面加上override(重写)关键字。虚方法可以在不同的继承类中有不同的实现,即为基类中定义的允许在派生类中重写的方法。

1)声明:

访问修饰符 virtual 函数返回类型 函数名(参数表) {函数体};

2)注意:

① 因为虚方法需要被子类调用,所以访问修饰符不能为private。

② 父类虚方法使用的什么访问修饰符,子类重写就必须用什么访问修饰符。

③ 在父类中声明的虚方法一般在子类中对其进行调用,会运用到base关键字。

3)虚方法练习:

class Person
{
    public Person(string name)
    {
        this.Name = name;
    }
    private string _name;
    public string Name { get => _name; set => _name = value; }
    //父类方法加virtual,子类用override重写该方法,就实现了多态 
    public virtual void SayHello()   
    {
        Console.WriteLine("我是父类的方法");
    }
}
//学生类和教师都继承于Person:
class Student : Person
{
    public Student(string name) : base(name) { }
    public override void SayHello()
    {
        Console.WriteLine($"我叫{this.Name}, 我是学生");
    }
}
class Teacher:Person
{
    public Teacher(string name) : base(name) { }
    public override void SayHello()
    {
        Console.WriteLine($"我叫{this.Name}, 我是老师");
    }
}
//然后在Main函数中使用多态:
static void Main(string[] args)
{
    Student st = new Student("学生");
    Teacher th = new Teacher("老师");
    Person[] p = { st, th };  //子类对象赋给父类
    for(int i = 0; i < p.Length; i++)
    {
        p[i].SayHello();
    }
    Console.ReadKey();
}

输出结果:

我叫学生, 我是学生

我叫老师, 我是老师

15.3 多态--抽象类

        当父类中的方法不知道如何去实现的时候,可以考虑将父类写成抽象类,将方法写成抽象方法,在类前面加关键字abstract,方法前面加abstract,抽象方法不能有函数体。有大括号,里面没有内容叫空实现。抽象类不允许创建对象和接口。

1)抽象类的特点:

  • 抽象类成员必须标记为abstract,并且不能有任何实现
  • 抽象类成员必须在抽象类中
  • 抽象类不能实例化
  • 子类继承抽象类后,必须把父类中的所有抽象成员都重写(除非子类也是一个抽象类,可以不重写)
  • 抽象成员的访问修饰符不能是private
  • 在抽象类中可以包含实例成员,并且抽象类的实例成员可以不被子类实现
  • 抽象类是有构造函数的,虽然不能被实例化
  • 如果父类的抽象方法中有参数,那么,继承这个抽象类的子类在重写父类的方法时必须传入对应的参数。如果抽象父类的抽象方法中有返回值,那么子类在重写抽象方法时,也必须要传入返回值

 2)抽象类示例:

abstract class Person
{
    //抽象方法不能有函数体
    public abstract void SayHello();
}
class Student : Person
{
    public override void SayHello()
    {
        Console.WriteLine("我是子类Student重写的抽象方法");
    }
}
class Teacher : Person
{
    public override void SayHello()
    {
        Console.WriteLine("我是子类Teacher重写的抽象方法");
    }
}
class Program
{
    static void Main(string[] args)
    {
        List<Person> clist = new List<Person>();
        Student st = new Student();
        Teacher th = new Teacher();
        clist.Add(st);
        clist.Add(th);
        foreach (Person p in clist)
        {
            p.SayHello();
        }
        Console.ReadKey();
    }
}

输出结果:

我是子类Student重写的抽象方法

我是子类Teacher重写的抽象方法

3)抽象类练习:求圆和长方形的面积和周长

//父类--形状
public abstract class Shape
{
    public abstract double GetArea();
    public abstract double GetPrimeter();
}
//子类--圆形
public class Circle : Shape
{
    private double _r;
    public double R { get => _r; set => _r = value; }
    //圆形的构造方法,需要传入r即半径
    public Circle(double r)
    {
        this.R = r;
    }
    public override double GetArea()
    {
        return Math.PI * R * R;
    }
    public override double GetPrimeter()
    {
        return Math.PI * R * 2;
    }
}
//子类--方形
public class Square : Shape
{
    private double _height;
    private double _weigh;
    public double Height { get => _height; set => _height = value; }
    public double Weigh { get => _weigh; set => _weigh = value; }
    //构造函数,需要传入长和高
    public Square(double height, double weigh)
    {
        this.Height = height;
        this.Weigh = weigh;
    }
    public override double GetArea()
    {
        return Height * Weigh;
    }
    public override double GetPrimeter()
    {
        return (Height + Weigh) * 2;
    }
}
class Program
{
    static void Main(string[] args)
    {
        Shape p = new Circle(5);
        double area = p.GetArea();
        double primeter = p.GetPrimeter();
        Console.WriteLine("圆的Area={0},圆的Primeter={1}", area, primeter);
        Shape s = new Square(10, 20);
        double s_area = s.GetArea();
        double s_primeter = s.GetPrimeter();
        Console.WriteLine("方形的Area={0},方形的Primeter={1}", s_area, s_primeter);
        Console.ReadKey();
    }
}

输出结果:

圆的Area=78.5398163397448,圆的Primeter=31.4159265358979

方形的Area=200,方形的Primeter=60

15.4 多态--接口

1)接口简介

  • 接口就是为了约束方法的格式(参数和返回值类型)而存在的,接口可以实现多继承,弥补单继承的缺陷。
  • 接口可以看成是一个特殊的抽象类,通过反编译看源码可知。
  • 接口中方法不用访问修饰符,因为CLR会自动添加,并且不能有方法体。

2)注意:

  • 如果一个类实现了某个接口,就必须得实现该接口中所有的方法
  • 接口要谨慎使用,防止出现接口污染!
  • 接口仅仅代表一种能力,实现该接口的类和接口没有继承关系
  • 接口是用来实现的,类是用来继承的。
  • 其实很多时候,看似可以不用接口,因为接口就是一个方法的约定,表明你这个类必须要有某些方法,但是不写接口也可以有这些方法,用了接口,就可以使用接口变量,统一调用,实现多态
  • 接口中只能定义方法,不能定义变量。

3)抽象类和接口的区别:

  • 当需要的各个对象之间存在父子类关系时,可以考虑使用抽象类,
  • 当各个对象之间不存在继承关系,只是有相同的能力时,而已考虑使用接口

4)接口的通俗理解:

  • 飞机会飞,鸟会飞,他们都继承了同一个接口“飞”;但是F22属于飞机抽象类,鸽子属于鸟抽象类。
  • 就像铁门木门都是门(抽象类),你想要个门我给不了(不能实例化),但我可以给你个具体的铁门或木门(多态);而且只能是门,你不能说它是窗(单继承);一个门可以有锁(接口)也可以有门铃(多实现)。门(抽象类)定义了你是什么,接口(锁)规定了你能做什么。(一个接口最好只能做一件事,你不能要求锁也能发出声音吧(接口污染))

 5) 练习1:

public interface IWeapon
{
    void Fire();
}
class Gun : IWeapon
{
    public void Fire()
    {
        Console.WriteLine("我是枪");
    }
}
class Sword : IWeapon
{
    public void Fire()
    {
        Console.WriteLine("我是剑");
    }
}
class Tank : IWeapon
{
    public void Fire()
    {
        Console.WriteLine("我是坦克");
    }
}
class Program
{
    static void Main(string[] args)
    {
        List<IWeapon> list = new List<IWeapon>();
        Gun gun = new Gun();
		Sword sw = new Sword();
		Tank ta = new Tank();
        list.Add(gun);
        list.Add(sw);
        list.Add(ta);
		foreach (IWeapon p in list)
        {
            p.Fire();
        }
        Console.ReadKey();
    }
}

输出结果:

我是枪

我是剑

我是坦克

6)练习2:

public interface ISwiming
{
    void Swiming();
}
public class RealDusk : ISwiming
{
    public void Swiming()
    {
        Console.WriteLine("真的鸭子用脚游泳");
    }
}
public class XPDusk : ISwiming
{
    public void Swiming()
    {
        Console.WriteLine("橡皮鸭子漂浮游泳");
    }
}
public class MTDusk : ISwiming
{
    public void Swiming()
    {
        Console.WriteLine("木头鸭子不能游泳");
    }
}
class Program
{
    static void Main(string[] args)
    {
        ISwiming iw = new RealDusk();
        iw.Swiming();
        Console.ReadKey();
    }
}

输出结果:真的鸭子用脚游泳

15.5 多态练习

用多态来实现将移动硬盘或者U盘或者MP3查到电脑上进行读写数据。

public abstract class MobieStorage
{
    public abstract void Read();
    public abstract void Write();
}
public class MobieDisk : MobieStorage
{
    public override void Read()
    {
        Console.WriteLine("这是移动硬盘的读取");
    }
    public override void Write()
    {
        Console.WriteLine("这是移动硬盘的写入");
    }
}
public class MP3Disk : MobieStorage
{
    public override void Read()
    {
        Console.WriteLine("这是MP3的读取");
    }
    public override void Write()
    {
        Console.WriteLine("这是MP3的写入");
    }
    public void PlayMusic()
    {
        Console.WriteLine("开始播放音乐");
    }
}
public class UPDisk : MobieStorage
{
    public override void Read()
    {
        Console.WriteLine("这是U盘的读取");
    }
    public override void Write()
    {
        Console.WriteLine("这是U盘的写入");
    }
}
public class Computer
{
    private MobieStorage ms;
    public MobieStorage Ms { get => ms; set => ms = value; }
    public void CpuWrite()
    {
        Ms.Write();
    }
    public void CpuRead()
    {
        Ms.Read();
    }
}
class Program
{
    static void Main(string[] args)
    {
        MobieStorage ms = new UPDisk();
        Computer cp = new Computer();
        //将ms传入字段里面
        cp.Ms = ms;
        cp.CpuRead();
        cp.CpuWrite();
        Console.ReadKey();
    }
}

15.6 综合练习 超市收银系统

1)商品类

//商品父类
class ProductFather
{
    string _name;
    double _price;
    string _id;
    public string Name { get => _name; set => _name = value; }
    public double Price { get => _price; set => _price = value; }
    public string Id { get => _id; set => _id = value; }
    public ProductFather(string name, double price, string id)
    {
        this.Name = name;
        this.Price = price;
        this.Id = id;
    }
}
class Acer : ProductFather
{
    public Acer(string name, double price, string id): base(name, price, id)
    {
    }
}
class Banana : ProductFather
{
    public Banana(string name, double price, string id): base(name, price, id)
    {
    }
}
class SanSung : ProductFather
{
    public SanSung(string name, double price, string id): base(name, price, id)
    {
    }
}
class JianYou : ProductFather
{
    public JianYou(string name, double price, string id): base(name, price, id)
    {
    }
}

2)仓库类

class CanKu
{
    List<List<ProductFather>> list = new List<List<ProductFather>>();//展示货物
    public void ShowPros()
    {
        foreach (var item in list)
        {
            Console.WriteLine("我们仓库有{0},价格是{1}元,有{2}            
            个",item[0].Name,item[0].Price, item.Count);
            //item:货架  item[0]:货架上第一个商品 //item
        }
    }
    public CanKu()
    {
        list.Add(new List<ProductFather>());
        list.Add(new List<ProductFather>());
        list.Add(new List<ProductFather>());
        list.Add(new List<ProductFather>());
    }
    //进货
    public void GetPros(string type, int count)
    {
        for (int i = 0; i < count; i++)
        {
            switch (type)
            {
                case "Acer":
                    list[0].Add(new Acer("红星笔记本", 7999, Guid.NewGuid().ToString()));
                    break;
                case "Banana":
                    list[1].Add(new Banana("香蕉", 15,Guid.NewGuid().ToString()));
                    break;
                case "JianYou":
                    list[2].Add(new JianYou("海天酱油", 30,Guid.NewGuid().ToString()));
                    break;
                case "SanSung":
                    list[3].Add(new SanSung("三星手机", 3000,Guid.NewGuid().ToString()));
                    break;
            }
        }
    }
    //取货
    public ProductFather[] QuPros(string type, int count)
    {
        ProductFather[] pros = new ProductFather[count];
        for (int i = 0; i < pros.Length; i++)
        {
            switch (type)
            {
                case "Acer":
                    //第一个[0]表示第一个货架,第二个[0]表示第一个商品
                    pros[i] = list[0][0];
                    list[0].RemoveAt(0);
                    break;
                case "Banana":
                    pros[i] = list[1][0];
                    list[1].RemoveAt(0);
                    break;
                case "JianYou":
                    pros[i] = list[2][0];
                    list[2].RemoveAt(0);
                    break;
                case "SanSung":
                    pros[i] = list[3][0];
                    list[3].RemoveAt(0);
                    break;
            }
        }
    return pros;
    }
}

3)打折类 


abstract class CalFather
{
    //计算打折后的钱
    public abstract double GetTotalMoney(double Money);
}
class CalNormal : CalFather
{
    //返回原价
    public override double GetTotalMoney(double Money)
    {
        return Money;
    }
}
class CalRate : CalFather
{
    private double _rate;
    public double Rate { get => _rate; set => _rate = value; }
    public CalRate(double rate)
    {
        this.Rate = _rate;
    }
    public override double GetTotalMoney(double Money)
    {
        return Money * this.Rate;
    }
}
class CalMN : CalFather
{
    private double _m;
    private double _n;
    public double M { get => _m; set => _m = value; }
    public double N { get => _n; set => _n = value; }
    public CalMN(double m, double n)
    {
        this.M = m;
        this.N = n;
    }
    public override double GetTotalMoney(double Money)
    {
        if (Money >= this.M)
        {
            return Money - ((int)(Money / this.M)) * this.N;
        }
        else
        {
            return Money;
        }
    }
}

4)超市类

class SuperMarket
{
    //创建仓库对象后,自动调用仓库中的构建函数,创建四个货架
    CanKu ck = new CanKu();
    //创建超市对象的时候,给仓库的货架上导入货物
    public SuperMarket()
    {
        ck.GetPros("Acer", 1000);
        ck.GetPros("Banana", 1000);
        ck.GetPros("JianYou", 1000);
        ck.GetPros("SanSung", 1000);
    }
    public void AskBuying()
    {
        Console.WriteLine("欢迎光临,请问您需要些什么");
        Console.WriteLine("我们有 Acer、JianYou、Banana、SanSung");
        string type = Console.ReadLine();
        Console.WriteLine("你需要多少");
        int count = Convert.ToInt32(Console.ReadLine());
        //去仓库取货
        ProductFather[] pros = ck.QuPros(type, count);
        //计算价钱
        double Money = GetMoney(pros);
        Console.WriteLine("您总共需要付{0}元", Money);
        Console.WriteLine("请选择你的打折方式 1--不打折 2--打九折 3--打85折 4--买300送50 5--买500送100");
        string input = Console.ReadLine();
        //通过简单工厂的设计模式根据用户的输入获得一个打折对象
        CalFather cal = GetCal(input);
        double calMoney = cal.GetTotalMoney(Money);
        Console.WriteLine("打完折后应付{0}元", calMoney);
    }
    public CalFather GetCal(string input)
    {
        CalFather cal = null;
        switch (input)
        {
            case "1":
                cal = new CalNormal();
                break;
            case "2":
                cal = new CalRate(0.9);
                break;
            case "3":
                cal = new CalRate(0.85);
                break;
            case "4":
                cal = new CalMN(300, 50);
                break;
            case "5":
                cal = new CalMN(500, 100);
                break;
        }
    return cal;
    }
    public double GetMoney(ProductFather[] pros)
    {
        double Money = 0;
        for (int i = 0; i < pros.Length; i++)
        {
            Money += pros[i].Price;
        }
        return Money;
    }
    public void ShowPros()
    {
        ck.ShowPros();
    }
}

5)主函数

class Program
{
    static void Main(string[] args)
    {
        //创建超市对象
        SuperMarket sm = new SuperMarket();
        //展示货物
        sm.ShowPros();
        //跟用户交互
        sm.AskBuying();
        Console.ReadKey();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值