这次一定要告诉你,OOP的特性多态到底该怎么用。最近在看了一个本书有一段说到继承,继承的拿来主义说的很好,但是一下子就到多态的特性,把继承和多态混为一滩。不开心,就不想再看了。我也很疑惑,就多找了几本书,对于多态的理解都是继承的关系。我去网上搜,发现能不多态讲的很明白很少。大家基本认为继承的糟糕特性,建议组合,但是多态仍然是继承的关系。我想问问如果继承就是多态,OOP直接就封装和多态好了,继承又不好用。但是事实就是继承,封装,多态是相互独立的特性,许多人不理解这些特性,所以代码写不好,代码写不好就有人写了设计模式纠正错误,设计模式还是不够细致就有人写了代码规范。这一切都是对OOP的误解和误用开始的,尤其是多态基本上好多人不解其意,到底多态是个什么,大家也说不清楚,相对于继承,封装,多态比较抽象没有找到现实的映射就导致被误用了。我最开始写的代码真的糟糕,只是把代码放到class中而已,这不是OOP。
现在我要把多态说明白,好让大家少一点弯路。
先从我们最开始结束的OOP编程语言时介绍多态的例子开始
动物,猫 ,狗 大家感觉到熟悉了吧,只要写OOP的必定用到的例子
abstract class Animal{
func run()
}
class Cat:Animal{
func run(){
//猫run
}
}
class Dog:Animal{
func run(){
//狗run
}
}
class Controller{
let cat:Animal = Cat()
let dog:Animal = Dog()
cat.run()
dog.run()
}
这个写完就告诉你这就是多态,父类指针可以调用子类的方法,这样完全是错误的。大家可以打印一下cat 的类还是Cat dog 的类还是Dog,这也只是普通的强制类型而已,只是这样写可以同ISA指针指向父类类型但是本身的类型状态并没有改变。再说继承只是拿来父类的东西用而已,根本构不成多态。如果是多继承的话,可是使用多态到也说的过去,但是单继承的话就不能了,本身状态并没有改变。在kotlin中甚至加入了强制类型推到,使用时不需要父类指向强制子类类型了,都是告诉我们继承不是多态,父类不能调用子类的方法好不,强制类型下只能是本类调用,只是你看到的类型声明告诉我们这个类型实现该方法,但是他的类型仍然是子类类型。
多态是说当前类又多个状态,那这个多个状态是什么呢?
interface LandInterface{
func run()
}
interface SkyInterface{
func fly()
}
class Cat:LandInterface{
func run(){
//猫run
}
}
class Bird:LandInterface,SkyInterface{
func run(){
//鸟跑
}
func fly(){
//鸟飞
}
}
class Controller{
let cat:Cat = Cat()
cat.run()
//看到这里大家就不开心了,写了两个接口怎么就多态了,没看出了
//那是在controller中这么写不对,加入一个controller需要鸟跑,一个controller需要鸟飞呢
let bird:Bird = Bird()
bird.run()
bird.fly()
}
//这里需要IOC的知识了,实际上IOC是正确写法,上边的这种写法本身就是错误的,是POP的写法,用啥写啥不是OOP
class Controller{
var bird:LandInterface?
bird?.run()
}
class Controller{
var bird:SkyInterface?
bird?.fly()
}
//这才是多态,一个类又多个状态。如果需要这个类其他状态那么扩展就好了。记住类的类型不改变,改变的只是当前的
//的状态,如果改变了类型那就是bug了。多态给予一个类更多可能性,一个类可以做很多的事情。但是对于封装多态是不好的,
//多态很好用,但是不是超人,只给它业务相关了状态就好,切勿滥用。
//我感觉方法重载去掉大家基本上就会好些了,因为有重载的原因大家就以为继承就是这样用,但是还有super啊应该规定重载必须super,
//不然就报错。官方sdk写的多好,把super去掉就不让你过。基本上就是你要重载如果不super说明不应该继承,真香。