[Explicação detalhada básica do C#] (15) Polimorfismo orientado a objetos

15.1 Introdução ao polimorfismo

1) O conceito de polimorfismo:

        Permitir que um objeto exiba vários estados (tipos) significa ter várias formas. No paradigma de programação orientada a objetos, o polimorfismo é freqüentemente expresso como "uma interface, múltiplas funções".

        Suponha que haja um mestre humano. Alimente diferentes animais. Quando diferentes objetos animais chamam métodos, o código repetido é freqüentemente modificado. A escalabilidade e a manutenção do código são ruins. Portanto, podemos usar uma classe Animal como parâmetro para permitir que diferentes animais herdem essa classe animal, que é o polimorfismo.

2) Três maneiras de alcançar o polimorfismo:

Método virtual (substituição virtual)

Classe abstrata (abstract)

interface

3) Os benefícios do polimorfismo:

        O aplicativo não precisa escrever chamadas de função para cada classe derivada, apenas a classe base abstrata precisa ser processada. Melhorar consideravelmente a capacidade de reutilização do programa. (herdar)

        As funções da classe derivada podem ser chamadas pelos métodos ou variáveis ​​de referência da classe base, o que é chamado de compatibilidade com versões anteriores, o que pode melhorar a escalabilidade e a capacidade de manutenção. (O verdadeiro papel do polimorfismo)

15.2 Polimorfismo -- métodos virtuais

        Adicione a palavra-chave virtual na frente do método da classe pai e adicione a palavra-chave override (substituir) na frente do nome do método quando a subclasse substituir o método. Métodos virtuais podem ter diferentes implementações em diferentes classes herdadas, ou seja, métodos definidos na classe base que permitem sobreposição em classes derivadas.

1) Declaração:

modificador de acesso função virtual tipo de retorno nome da função (lista de parâmetros) {corpo da função};

2) Observação:

① Como os métodos virtuais precisam ser chamados por subclasses, o modificador de acesso não pode ser privado.

② Qual modificador de acesso é usado pelo método virtual da classe pai, qual modificador de acesso deve ser usado para reescrever a subclasse.

③ O método virtual declarado na classe pai geralmente é chamado na subclasse e a palavra-chave base será usada.

3) Prática do método virtual:

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();
}

Resultado de saída:

Eu sou um estudante, eu sou um estudante

meu nome é professor, eu sou professor

15.3 Polimorfismo -- classe abstrata

        Quando o método na classe pai não sabe como implementá-lo, você pode considerar escrever a classe pai como uma classe abstrata e o método como um método abstrato. Adicione a palavra-chave abstract na frente da classe e abstract na frente do método O método abstrato não pode ter um corpo de função. Existem chaves e não há conteúdo interno, o que é chamado de implementação vazia. Classes abstratas não permitem a criação de objetos e interfaces.

1) As características das classes abstratas:

  • Os membros da classe abstrata devem ser marcados como abstratos e não devem ter nenhuma implementação
  • Os membros da classe abstrata devem estar na classe abstrata
  • Classes abstratas não podem ser instanciadas
  • Após a subclasse herdar a classe abstrata, todos os membros abstratos na classe pai devem ser reescritos (a menos que a subclasse também seja uma classe abstrata, ela não pode ser reescrita)
  • O modificador de acesso de um membro abstrato não pode ser privado
  • Membros de instância podem ser incluídos em classes abstratas, e membros de instância de classes abstratas não podem ser implementados por subclasses
  • Classes abstratas possuem construtores, embora não possam ser instanciadas
  • Se houver parâmetros no método abstrato da classe pai, a subclasse herdada dessa classe abstrata deve passar os parâmetros correspondentes ao reescrever o método da classe pai. Se houver um valor de retorno no método abstrato da classe pai abstrata, a subclasse também deve passar o valor de retorno ao reescrever o método abstrato

 2) Exemplo de classe abstrata:

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();
    }
}

Resultado de saída:

Eu sou um método abstrato substituído pela subclasse Aluno

Eu sou um método abstrato substituído pela subclasse Professor

3) Exercício abstrato: encontre a área e o perímetro de círculos e retângulos

//父类--形状
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();
    }
}

Resultado de saída:

Área do círculo = 78,5398163397448, Primer do círculo = 31,4159265358979

Área quadrada = 200, Primer quadrado = 60

15.4 Polimorfismo -- Interfaces

1) Introdução à interface

  • As interfaces existem para restringir o formato dos métodos (parâmetros e tipos de valor de retorno).As interfaces podem implementar herança múltipla para compensar os defeitos da herança única.
  • A interface pode ser considerada como uma classe abstrata especial, que pode ser vista observando o código-fonte por meio da descompilação.
  • Os métodos nas interfaces não precisam de modificadores de acesso, porque o CLR os adicionará automaticamente e não pode haver corpos de método.

2) Observação:

  • Se uma classe implementa uma interface, ela deve implementar todos os métodos na interface
  • A interface deve ser usada com cuidado para evitar a poluição da interface!
  • Uma interface representa apenas uma capacidade, e a classe que implementa a interface não tem relação de herança com a interface
  • Interfaces são usadas para implementação e classes são usadas para herança.
  • Na verdade, muitas vezes, parece que você não pode usar a interface, porque a interface é um acordo de método, indicando que sua classe deve ter determinados métodos, mas você também pode ter esses métodos sem escrever a interface. pode usar a variável de interface, chamada unificada para atingir o polimorfismo
  • Interfaces podem apenas definir métodos, não variáveis.

3) A diferença entre classe abstrata e interface:

  • Quando há um relacionamento pai-filho entre os objetos necessários, você pode considerar o uso de uma classe abstrata.
  • Quando não há relação de herança entre os objetos, mas apenas possuem as mesmas capacidades, a interface foi considerada

4) Compreensão popular da interface:

  • Aviões podem voar, pássaros podem voar, ambos herdam a mesma interface "voar"; mas F22 pertence à classe abstrata dos aviões e os pombos pertencem à classe abstrata dos pássaros.
  • Assim como portas de ferro e madeira são todas portas (classe abstrata), não posso lhe dar uma porta que você queira (não pode ser instanciada), mas posso lhe dar uma porta específica de ferro ou madeira (polimórfica); e só pode ser uma porta, não se pode dizer que é uma janela (herança única); uma porta pode ter uma fechadura (interface) ou uma campainha (múltiplas implementações). Portas (classes abstratas) definem o que você é, interfaces (fechaduras) definem o que você pode fazer. (É melhor que uma interface só possa fazer uma coisa, você não pode pedir um bloqueio para fazer um som (poluição da interface))

 5) Exercício 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();
    }
}

Resultado de saída:

eu sou uma arma

eu sou a espada

eu sou um tanque

6) Exercício 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();
    }
}

Saída: patos reais nadam com os pés

15.5 Exercícios de Polimorfismo

Use polimorfismo para realizar o disco rígido móvel ou disco U ou MP3 para o computador para leitura e gravação de dados.

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  Sistema de caixa de supermercado

1) Categoria de mercadoria

//商品父类
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) classe de armazém

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) Descontos 


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) Supermercado

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) Função principal

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

おすすめ

転載: blog.csdn.net/Y1RV1NG/article/details/131034643