python's twenty-first day for me 抽象类和接口类以及多态
归一化设计:
不管是哪一个类的对象,都调用同一个函数去完成相似的功能。
class Alipay: def pay(self,money): print('使用支付宝支付了%s' % money) class QQpay: def pay(self,money): print('使用QQ支付了%s元' % money) def pay(way,money): # 以上两个类都使用了pay方法去完成相似的功能, way.pay(money) # 所以可定义一个***相同的函数名***来完成这个功能,这种就叫做归一化设计。 a = Alipay() q = QQpay() pay(a,100) # 使用支付宝支付了100 pay(q,100) # 使用QQ支付了100元
依赖倒置原则:
高层模块不应该依赖底层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现变成。
抽象类: 是python中定义类的一种规范。
如果遇到抽象类 记得按照抽象类中的规范一一实现对应的方法。
抽象即抽取类似或者说比较像的部分。抽象最主要的作用就是划分类别,抽象知识分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类。抽象是一种特殊的类,它的特殊之处在于只能被继承,不能被实例化。
抽象类的本质还是类,指的是一组类的相似性,包括数据属性和函数属性。
接口类:
接口类只强调函数属性的相似性,python中并没有接口类这种概念。
接口类的概念来自于JAVA,
java类没有多继承,所以用接口,接口可以实行按多继承。
接口隔离原则:
使用多个专门的接口,而不使用单一的总接口。
接口提取了一群类共同的函数,可以把接口当做一个函数的集合。
然后让子类去实现接口中的函数。
这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。
归一化,让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。
比如:我们定义一个动物接口,接口里定义了有跑、吃、呼吸等接口函数,这样老鼠的类去实现了该接口,松鼠的类也去实现了该接口,由二者分别产生一只老鼠和一只松鼠送到你面前,即便是你分别不到底哪只是什么鼠你肯定知道他俩都会跑,都会吃,都能呼吸。
再比如:我们有一个汽车接口,里面定义了汽车所有的功能,然后由本田汽车的类,奥迪汽车的类,大众汽车的类,他们都实现了汽车接口,这样就好办了,大家只需要学会了怎么开汽车,那么无论是本田,还是奥迪,还是大众我们都会开了,开的时候根本无需关心我开的是哪一类车,操作手法(函数调用)都一样
# 描述动物园 # 会游泳的 会走路的 会爬树的 会飞的 # 老虎 # 青蛙 # 天鹅 # 猴子 # 所有会飞的动物 具有一些会飞的动物的特性 # 所有会走的动物 具有一些会走的动物的特性 from abc import ABCMeta,abstractmethod class FlyAnimal(metaclass=ABCMeta): @abstractmethod def fly(self):pass @abstractmethod def cal_fly_speed(self):pass @abstractmethod def cal_fly_height(self):pass class WalkAnimal(metaclass=ABCMeta): @abstractmethod def walk(self):pass class SwimAnimal(metaclass=ABCMeta): @abstractmethod def swim(self):pass class Tiger(WalkAnimal,SwimAnimal): def walk(self):pass def swim(self):pass class Monkey(WalkAnimal): def walk(self):pass def climb(self):pass class Swan(FlyAnimal,WalkAnimal,SwimAnimal): def swim(self):pass def walk(self):pass def fly(self):pass def cal_fly_speed(self):pass def cal_fly_height(self):pass
接口类的作用:
在java中,能够满足接口隔离原则,且完成多继承的约束。
在python中,满足接口隔离原则,由于python本身支持多继承,所以就不需要接口的概念。
抽象类和接口类做的事情:建立规范,制定一个类的metaclass是ABCMeta,那么这个类就变成了一个抽象类(接口类),这个类的主要功能就是建立一个规范,抽象类中所有被abstractmethod装饰的方法都必须被继承的子类实现,否则就会在实例化阶段就会报错。
from abc import ABCMeta,abstractmethod class Payment(metaclass=ABCMeta): # 抽象类 接口类 规范和约束 metaclass指定的是一个元类 @abstractmethod def pay(self,money):pass # 抽象方法 规定此类下的字类都必须拥有pay这个方法名。 class Alipay(Payment): # 继承 Payment def pay(self,money): # 方法名必须是pay print('使用支付宝支付了%s元' % money) class QQpay(Payment): # 继承 Payment def pay(self,money): # 方法名必须是pay print('使用QQ支付了%s元' % money) class Wechatpay(Payment): # 继承 Payment def pay(self,money): # 方法名必须是pay print('使用微信支付了%s元' % money) a = Alipay() q = QQpay() w = Wechatpay() a.pay(100) # 使用支付宝支付了100元 q.pay(100) # 使用QQ支付了100元 w.pay(100) # 使用微信支付了100元
总结:无论是抽象类还是接口类metaclass = ABCMeta 都不可以被实例化。
抽象类和接口类:
在python中:
1,并没有什么不同,都是用来约束子类中的方法的。
2,只要抽象类和接口类中被abstractmethod装饰的方法,都需要被子类实现。
3,需要注意的是,当多个类之间有相同的功能也有不同的功能的时候,应该采用多个接口类来进行分别的约束。
在java中:
1,抽象类和接口截然不同。
2,抽象类的本质还是一个类,是类就必须遵循单继承的规则,所以一个子类如果被抽象类约束,那么它只能被一个父类控制。
3,当多个类之间有相同的功能也有不同的功能的时候 java 只能用接口来解决问题。
多态:
java c++ c# ----- 强类型语言。传入参数必须表明是什么类型的参数。
如:def func(int a) : pass
相同数据类型之间做运算。
shell语言 -----弱类型语言。如:可以直接运算 1+‘1’
介于 强类型 与 弱类型 之间 ----- python 动态强类型语言。
相同数据之间类型之间做运算。
java 多态:在一个类之下发展出来的多个类的对象都可传入以作为参数传入。
无论是python2x,python3x 都天生自带多态效果。
多态和鸭子类型:
多态通过继承实现:
java在一个类之下发展出来的多各类的对象都可以作为参数传入一个函数或者方法。
在python中不需要可以实现多态,因为python本身自带多态效果。
鸭子类型:
不是通过具体的继承关系来约束某些类中必须有哪些方法名。
是通过一种约定俗成的概念来保证在多个类中相似的功能叫相同的名字。