黑马C#笔记05:多态(虚方法实现多态),抽象类(实现多态),访问修饰符,简单工厂模式,序列化和反序列化,部分类,密封类,接口(实现多态),超市收银系统,MD5

.net基础教程 12-13448:48.net 基础教程 12-13

-------------------------------------

https://www.bilibili.com/video/av32101840?p=10

多态

实现多态的三种方法:1.虚方法;2抽象类;3.接口

虚方法实现多态-注:用虚方法子类可以实现多态,也可以不实现多态

虚方法多态实现:1父类的方法用virtual写成虚方法;2子类的同名方法用override关键字覆盖父类同名方法.此时使用父类对象指向子类对象,父类对象调用子类同名override方法实现多态(不调用父类自己的方法,而是调用子类的override方法.)

抽象类-实现多态

抽象类必须使用abstract关键字
抽象成员(方法)只能出现在抽象类中.抽象成员(方法)必须使用abstract关键字.
抽象类的抽象方法禁止实现
抽象类可以有非抽象成员(方法),对自己无意义,但对子类有用
抽象类的对象不能new实例化(即只有非抽象类的对象才能实例化)
非抽象的子类实现父类的抽象方法时需要使用override关键字
抽象类有构造函数,虽然无法实例化
抽象类可以有virtual方法-对自己无意义,对子类有用
(后代可以实现多态,也可以不实现多态.对比:普通方法-后代不能实现动态;抽象方法-后代必须实现多态;虚方法-后代可以实现动态,也可以不实现多态)
多态:可以使用抽象父类的对象(抽象类不能new实例化对象)引用它的非抽象子类对象,并调用子类方法(父类成员必须满足多态条件,子类成员必须override覆盖)

抽象类实现多态简单示例:


全部代码如下:

namespace App018_抽象类 {
    class Program {
        static void Main(string[] args) {
            //动物类 test = new 动物类();//注意!抽象类不能实例化

            //抽象类实现多态
            动物类[] 动物们 = new 动物类[4];
            //使用父类对象指向子类对象
            动物们[0] = new 猫咪类();
            动物们[1] = new 狗狗类();
            动物们[2] = new 猪头类();
            动物们[3] = new 驴子类();
            foreach (动物类 小动物 in 动物们) {
                小动物.叫();
            }
            Console.ReadKey();
        }
    }
    /// <summary>
    /// 抽象类.可以有抽象方法和非抽象方法
    /// 抽象方法禁止实现,由派生类实现.
    /// (派生类也可以是抽象方法,但总归会有派生类的派生类...实现)
    /// </summary>
    public abstract class 动物类 {
        public abstract string 名字 { get; set; }
        public abstract void 叫();
        //注意:抽象方法禁止实现!不可以有方法体! 
        //抽象方法必须由子类实现!(除非子类也是抽象方法.但子类的派生类总归要实现!)
    }
    class 猫咪类 : 动物类 {
        public override string 名字 { get; set; }
        public override void 叫() {
            Console.WriteLine("我是猫咪.我喵喵喵叫!");
        }
    }
    class 狗狗类 : 动物类 {
        public override string 名字 { get; set; }
        public override void 叫() {
            Console.WriteLine("我是狗狗.我汪汪汪叫!");
        }
    }
    class 猪头类 : 动物类 {
        public override string 名字 { get; set; }
        public override void 叫() {
            Console.WriteLine("我是猪头.我吼吼吼叫!");
        }
    }
    class 驴子类 : 动物类 {
        public override string 名字 { get; set; }
        public override void 叫() {
            Console.WriteLine("我是驴子.我昂昂昂叫!");
        }
    }
}

程序输出:

我是猫咪.我喵喵喵叫!
我是狗狗.我汪汪汪叫!
我是猪头.我吼吼吼叫!
我是驴子.我昂昂昂叫!

再以电脑和移动设备(手机/U盘/移动硬盘等)为例

写个抽象类实现移动设备插电脑读写,代码如下:

namespace 抽象类示例_移动设备插电脑读写 {
    class Program {
        static void Main(string[] args) {
            
            电脑 我的电脑 = new 电脑();
            我的电脑.插入的移动设备 = new 手机();
            我的电脑.让设备写数据();
            我的电脑.让设备读数据();
            Console.ReadKey();
        }
    }
    public class 电脑 {
        private 移动设备 _插入的移动设备;
        public 移动设备 插入的移动设备 { get => _插入的移动设备; set => _插入的移动设备 = value; }

        public void 让设备读数据() {
            插入的移动设备.读数据();
        }
        public void 让设备写数据() {
            插入的移动设备.写数据();
        }
    }

    public abstract class 移动设备{
        public abstract void 读数据();
        public abstract void 写数据();
    }
    public class 优盘 : 移动设备 {
        public override void 写数据() {
            Console.WriteLine("优盘写数据");
        }
        public override void 读数据() {
            Console.WriteLine("优盘读数据");
        }
    }
    public class 移动硬盘 : 移动设备 {
        public override void 写数据() {
            Console.WriteLine("移动硬盘写数据");
        }
        public override void 读数据() {
            Console.WriteLine("移动硬盘读数据");
        }
    }
    public class 手机 : 移动设备 {
        public override void 写数据() {
            Console.WriteLine("手机写数据");
        }
        public override void 读数据() {
            Console.WriteLine("手机读数据");
        }
    }
}

其中抽象父类为移动设备:

    public abstract class 移动设备{
        public abstract void 读数据();
        public abstract void 写数据();
    }

它的非抽象子类有:优盘,移动硬盘,手机

作为调用这些类的主体是电脑类的对象:

    public class 电脑 {
        private 移动设备 _插入的移动设备;
        public 移动设备 插入的移动设备 { get => _插入的移动设备; 
            set => _插入的移动设备 = value; }

        public void 让设备读数据() {
            插入的移动设备.读数据();
        }
        public void 让设备写数据() {
            插入的移动设备.写数据();
        }
    }

当我们插入的移动设备是手机时,代码及运行效果如下:

当我们插入的移动设备是优盘移动硬盘时,只需简单修改代码:


而且,以后即使再增加更多的移动设备子类,也无须变更现有类代码耦合性大大降低...

访问修饰符

public:公开的,所有类都可以访问
protected:受保护的,当前类和子类可以访问(可以跨程序集/项目)
private:仅当前类可以访问
internal:仅当前程序集(项目)可以访问.在同一项目中,internal和public等价.
protected internal:仅当前程序集的当前类和子类可以访问

1.修饰类的只有public和internal

2.可访问性不一致.
子类的访问权限不能高于父类的访问权限,否则会暴露父类的成员

设计模式-简单工厂设计模式


使用多态实现简单工厂模式:每次用户要求不同的具体子类产品时,只需给出父类产品即可(利用多态父类产品指向具体子类产品).因此无论客户要求哪种具体子类产品,工厂核心只需给客户父类产品 即可.

序列化和反序列化

概念

序列化:将对象转化为二进制

反序列化:将二进制还原为对象

作用:传输数据

方法

序列化:

1.在类前面加入序列化标记[Serializable];2.通过FileStream和BinaryFormatter生成序列化.如下为序列化简单示例:

以下是反序列化示例,通过反序列化上例产生的文件而反序列化对象:

部分类

使用partial关键字修饰的类为部分类.部分类允许多个人共写一个类.

对程序来说,使用partial修饰的类仍旧是同一个类并且只存在这一个类.

密封类

使用关键字sealed修饰的类为密封类.密封类不能被任何类继承.

接口-实行多态

接口概念

接口不能被实例化,为了多态,也不能实现(只能被子类继承且必须实现),它只允许有禁止实现的成员.

接口的成员只能有方法(禁止实现.不能有方法体),自动属性(不可以有普通属性),索引器和事件.

接口中的成员(自动属性或方法)不允许添加访问修饰符.接口的成员默认是public(不能也没必要添加public修饰符)

接口禁止存在字段成员(接口不允许存在数据)和构造函数

接口可以继承接口,且可以多继承.类可以继承最多1个类+多个接口,此时继承的类必须写于继承的接口之前.

 

我们来写一个接口简单示例

首先看类图

代码运行效果如下:

代码如下:

namespace App021_接口 {
    class Program {
        static void Main(string[] args) {
            //接口实现多态
            //IFlyable flyObj = new Swan();
            //IFlyable flyObj = new Hawk();
            IFlyable flyObj = new Parrot();
            //IFlyable flyObj = new Helicopter();
            //IFlyable flyObj = new Jordan();
            flyObj.Fly();

            ISpeak spkObj= new Parrot();
            //ISpeak spkObj = new Jordan();            
            spkObj.Speak();

            Console.ReadKey();
        }
    }
    class Bird {
        public double Wings {
            get;
            set;        
        }
        public void DrinkAndEat() {
            Console.WriteLine("我会吃会喝");
        }
    }
    interface IFlyable {
        void Fly();
    }
    interface ISpeak {
        void Speak();
    }
    class Swan : Bird, IFlyable {
        public void Fly() {
            Console.WriteLine("天鹅会飞");
        }
    }
    class Hawk : Bird, IFlyable {
        public void Fly() {
            Console.WriteLine("鹰会飞");
        }
    }
    class Parrot : Bird, IFlyable,ISpeak {
        public void Fly() {
            Console.WriteLine("鹦鹉会飞");
        }
        public void Speak() {
            Console.WriteLine("鹦鹉会说人话");
        }
    }
    class Cock : Bird {
        //公鸡不会飞,所以不继承IFlyable接口
    }
    class Hen : Bird {
        //母鸡不会飞,所以不继承IFlyable接口
    }
    class Helicopter : IFlyable {
        public void Fly() {
            Console.WriteLine("直升机用螺旋桨飞");
        }
    }
    class Jordan : IFlyable, ISpeak {
        public void Fly() {
            Console.WriteLine("飞人乔丹在篮球场飞");
        }
        public void Speak() {
            Console.WriteLine("飞人乔丹会说话");
        }
    }
}

显式实现接口

超市收银系统

md5

ToString(string)方法中格式参考:https://docs.microsoft.com/zh-cn/dotnet/api/system.byte.tostring?view=netframework-4.8#System_Byte_ToString_System_String_

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值