|
接口在C#、JAVA等现代语言中比较常用,它是对面向对象编程的一种很好的补充。
1、单纯使用继承的局限性
现实中的事物从不同角度来看,往往有多种特性。而传统的面向对象思想以继承为基础,有时显得非常死板。
继承的含义是:如果A继承B,那么“A是一种B”。例如人继承动物,则人是一种动物;同理猫也是动物,狗也是动物,海象也是动物。
这个思想看似比较接近现实,但现实中分类往往不止有一个角度,例如同样是狗,它俩就不太像:
如果以 可以揪着毛抓起来 作为分类条件,那么应该这么分,它俩是一类:
它俩是一类:
这么说的话,要不要以 长毛动物 和 短毛动物 作为基类呢?似乎还是不大对,如果以“是否会抓老鼠”作为判断依据又要重新分类了。
由于继承的方式只能从一个角度形成继承关系,如果需求比较复杂就会捉襟见肘。也有很多语言支持“多重继承”,就是一个类可以有多个基类。
多重继承看似很美好,但工程实践证明这样设计很可能弊大于利。所以Java和C#等工程化的语言都摒弃了多重继承。
2、从特性和功能出发,代替继承的思路
前面的例子太萌了,换个理性一点的例子。如果简单将设备分为输入设备和输出设备,可形成下面的设计图:
问题来了,手机是输入设备还是输出设备?
虽然换一种继承思路可能可以解决问题,但从中可以看出“继承”本身是有局限性的。如果我们把需要关心的“功能和特性”列出表来,实际上是这样的:
单纯从一个角度分类,远远不如像这样把功能摊开的好。如果把左边的每个“可XXXX”看做一种接口(接口这个名词翻译得有问题,应当理解为“满足的协议”或“承诺可进行的操作”),接口定义像这样写:- // 可按下按键的“协议”
- interface IPressButton
- {
- // 按下某个按键
- void Press(int button);
- }
- // 可插USB的“协议”
- interface IUSB
- {
- // 插USB
- void PlugUSB();
- }
复制代码 所有的具体类型,要根据是否满足协议来设计:- class 键盘 : IPressButton, IUSB
- {
- public void Press(int b)
- {
- Console.WriteLine("按下键盘"+b+"键");
- }
- public void PlugUSB() { }
- }
- class 鼠标 : IPressButton, IUSB
- {
- public void Press(int b)
- {
- Console.WriteLine("按下鼠标"+b+"键");
- }
- public void PlugUSB() { }
- }
- class 显示器 : IPressButton
- {
- public void Press(int b)
- {
- Console.WriteLine("按下显示器"+b+"键");
- }
- }
- class 手机 : IPressButton, IUSB
- {
- public void Press(int b) {
- Console.WriteLine("按下手机"+b+"键");
- }
- public void PlugUSB() { }
- }
复制代码 可以看到,四种物体都可以按下按钮,但是显示器不支持USB(假设这种显示器不支持)。
创建物体的代码没有区别:- 键盘 k1 = new 键盘();
- 键盘 k2 = new 键盘();
- 鼠标 m1 = new 鼠标();
- 手机 h1 = new 手机();
- 显示器 tv1 = new 显示器();
- 显示器 tv2 = new 显示器();
复制代码 在这种设计下,很多功能的实现方便。
需求1、统一按下所有物体的按键。- List<IPressButton> list = new List<IPressButton> {
- k1,k2, m1, h1, tv1, tv2
- };
- // 按下所有物体的按钮
- foreach (IPressButton obj in list)
- {
- obj.Press(1);
- }
复制代码 需求2、插某个物体的USB接口- // 插鼠标USB
- IUSB usbDevice = m1;
- usbDevice.PlugUSB();
- // 插手机USB
- usbDevice = h1;
- h1.PlugUSB();
- // 插显示器USB,插不了
- usbDevice = tv2; // !错误,类型不匹配
复制代码 更多的例子不再列举,相信如果看懂了上面的例子,就知道接口的灵活性体现在哪里了。 :)
3、Unity中是否要使用接口
别忘了其实除了接口和继承,还有另一种很好的扩展类的方法:组合。
而且Unity把“组合”的方法推而广之,形成了GameObject - Component体系,也就是组件化设计。
前面的例子里,我用了接口变量指代物体。其实在Unity中,还支持用组件来指代物体。至少从游戏开发实践来说,大部分时候组件比接口更为常用。
很多UI框架中大量使用接口,这是UI本身的复杂性决定的。接口在复杂的逻辑架构中也有用武之地。
建议在Unity中一定要优先学好掌握好组件式程序设计的思想,在制作更复杂的系统和框架时,可以考虑使用接口。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|