C#学习笔记 13.01
(学习视频来自bilibili的传智播客赵老师基础教学视频)
接口,上一篇剩下的最后一个多态
如果一个程序要求有扩展性,那么就要提取一个父类,这样在扩展的时候让新的类去击沉父类,父类中要提供子类都有的功能。
从一个例子来讲,U盘,移动硬盘,MP3,这三个东西都同时有被读写的功能,MP3又有一个播放的功能,这一堆东西中又可能增加上,手机,MP4等等,所以这就要求有扩展性。
当这些东西插在电脑上的时候,可以被电脑读写数据。
那么如果我们不用多态这个概念,那么我们从电脑的角度讲,读写不同设备的数据的时候就要调用不同对象的方法,而一旦我们用了多态这个思想,那么电脑上只需要抽象一个父类(移动存储设备),那么只需要调用这个父类的读写方法就可以解决了。
抽象类不能被实例化,但是抽象类可以作为传入参数,就像我们前面的 ArrayList.Add()一样,这个传入参数就是一个父类 object 由于里氏转换,子类可以赋值给父类,所以我们可以在这里输入各种类型的参数。
访问修饰符
public 公开的
private 私有的,只能在当前类内部访问
protected 受保护的,除了在当前类中访问外,在其子类中也可以访问。
internal 只能在当前程序集(项目)中访问
修饰类的是 public internal
这些都能用来修饰类的成员。。。。。。
设计模式 : 简单工厂设计模式
这是一个思维方式,视频推荐了一本书《大话设计模式》
父类中有这么一个构造函数,他可以通过参数来判断实例化何种子类对象,由于里氏转换,实例化的子类对象可以赋值给父类,由于抽象方法在子类实现,父类实际上又可以调用到子类的方法,这样一来就让一个类可以实现其多种子类的功能,表现在外的就是我们的代码具有极强的扩展性。
举个栗子
超市有三种打折方式,后面还可能会有更多的打折方式所以就应该有拓展性。
在这个例子中,我们把上一章提出又解决的问题也融入了代码。
但是又有了一个新的问题,如果想要接收价格并赋值给 _jiaGe 字段这个只在父类中写一次,应该怎么实现呢? 求教。。。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _18_ChaoShiJieZhang
{
class Program
{
static void Main(string[] args)
{
JieZhang(502, JieZhangFangShi.满减结账);
Console.ReadKey();
}
public static void JieZhang(double jiaGe, JieZhangFangShi jzfs)
{
JieZhang jz = null;//尽管抽象类不能实例化,但是声明变量赋值为空是没问题的
switch ((int)jzfs)
{
case 0:
jz = new YuanJia(jiaGe);
break;
case 1:
jz = new ManJian(jiaGe);
break;
case 2:
jz = new DaZhe(jiaGe);
break;
default:
break;
}
jz.ZuiZhongJia();
}
}
public enum JieZhangFangShi
{
原价结账,
满减结账,
打折结账
}
public abstract class JieZhang
{
protected double _jiaGe, _shiFu;
public double JiaGe
{
get { return _jiaGe; }
}
public double ShiFu
{
get { return _shiFu; }
}
public abstract void ZuiZhongJia();
}
public class YuanJia : JieZhang
{
public YuanJia(double jiaGe)
{
this._jiaGe = jiaGe;
}
public override void ZuiZhongJia()
{
Console.WriteLine("原价付款{0}元", this._jiaGe);
}
}
public class DaZhe : JieZhang
{
public DaZhe(double jiaGe)
{
this._jiaGe = jiaGe;
}
public override void ZuiZhongJia()
{
this._shiFu = this._jiaGe * 0.9;
Console.WriteLine("打9折结账,原价{0}元,实付{1}元", this._jiaGe, this._shiFu);
}
}
public class ManJian : JieZhang
{
public ManJian(double jiaGe)
{
this._jiaGe = jiaGe;
}
public override void ZuiZhongJia()
{
this._shiFu = this._jiaGe - ((int)(this._jiaGe / 100) * 10.5);
Console.WriteLine("满100减10.5,原价{0}元,实付{1}元", this._jiaGe, this._shiFu);
}
}
}
思考一下
这么写的话,当我们需要增加一种结账方式的时候,我们要新加上一个类,继承 JieZhang 这个父类,并实现 ZuiZhongJia 这个方法。
而且在判断的函数中,需要加一个 case 。。我这么写的话呢,还要在枚举类中加一个枚举。
那么问题来了,这不是也乱七八糟的加了一堆代码么,优势何在?
我思前想后了一下,优势应该就体现在大项目团队协作上,比如我们身处一个超市的管理系统中,而我呢,就负责一个收银部分折扣功能的代码,那么在主函数中,给出来这么一段关于结账的语句,这就可以了,定下了,不能随便改了。。。这种写法就可以实现,因为即使新增功能,所有的东西都和主函数中的语句无关,不需要其他部门配合,只需要把自己手里的收拾好就够了。
。。。。大概,是这样吧?。。。。
序列化
……因为我不是很能用得上,视频也很糊…… 嗯 就酱……
序列化:将对象转化为二进制
反序列化:将二进制转化为对象
作用:传输数据
- 将要序列化的对象所在的类标记为可以被序列化(在类前面加【Serializable】)
- 用 using 搞一个写入文件的流
- 实例化一个序列化对象
- 把这玩意按进一个流里面
- 客户端接收这个流
- 反序列化
- 强转配输出
- 然后就。。传输完成了?
- 嗯……就酱……