1, 抽象类 -- 类似接口
接口的概念:
自己提供给使用者来调用自己功能的方式 \ 方法 \ 入口,
1.1,java 中接口 interface
================= 第一部分: Java 语言中的接口很好的展现了接口的含义: IAnimal.java
- /*
- * Java 的 Interface 接口的特征:
- * 1)是一组功能的集合, 而不是一个功能
- * 2)接口的功能用于交互, 所有的功能都是 public, 即别的对象可操作
- * 3)接口只定义函数, 但不涉及函数实现
- * 4)这些功能是相关的, 都是动物相关的功能, 但光合作用就不适宜放到 IAnimal 里面了 */
- package com.oo.demo;
- public interface IAnimal { public void eat();
- public void run();
- public void sleep();
- public void speak();
- }
================= 第二部分: Pig.java: 猪 " 的类设计, 实现了 IAnnimal 接口
- package com.oo.demo;
- public class Pig implements IAnimal{ // 如下每个函数都需要详细实现
- public void eat(){
- System.out.println("Pig like to eat grass");
- }
- public void run(){
- System.out.println("Pig run: front legs, back legs");
- }
- public void sleep(){
- System.out.println("Pig sleep 16 hours every day");
- }
- public void speak(){
- System.out.println("Pig can not speak"); }
- }
================= 第三部分: Person2.java
- /*
- * 实现了 IAnimal 的 "人", 有几点说明一下:
- * 1)同样都实现了 IAnimal 的接口, 但 "人" 和 "猪" 的实现不一样, 为了避免太多代码导致影响阅读, 这里的代码简化成一行, 但输出的内容不一样, 实际项目中同一接口的同一功能点, 不同的类实现完全不一样
- * 2)这里同样是 "人" 这个类, 但和前面介绍类时给的类 "Person" 完全不一样, 这是因为同样的逻辑概念, 在不同的应用场景下, 具备的属性和功能是完全不一样的 */
- package com.oo.demo;
- public class Person2 implements IAnimal {
- public void eat(){
- System.out.println("Person like to eat meat");
- }
- public void run(){
- System.out.println("Person run: left leg, right leg");
- }
- public void sleep(){
- System.out.println("Person sleep 8 hours every dat");
- }
- public void speak(){
- System.out.println("Hellow world, I am a person");
- }
- }
1.2, 为何要用接口
接口提取了一群类共同的函数, 可以把接口当做一个函数的集合.
然后让子类去实现接口中的函数.
这么做的意义在于归一化, 什么叫归一化, 就是只要是基于同一个接口实现的类, 那么所有的这些类产生的对象在使用时, 从用法上来说都一样.
归一化的好处在于:
归一化让使用者无需关心对象的类是什么, 只需要的知道这些对象都具备某些功能就可以了, 这极大地降低了使用者的使用难度.
归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合
就好象 linux 的泛文件概念一样, 所有东西都可以当文件处理, 不必关心它是内存, 磁盘, 网络还是屏幕(当然, 对底层设计者, 当然也可以区分出 "字符设备" 和 "块设备", 然后做出针对性的设计: 细致到什么程度, 视需求而定).
再比如: 我们有一个汽车接口, 里面定义了汽车所有的功能, 然后由本田汽车的类, 奥迪汽车的类, 大众汽车的类,
他们都实现了汽车接口, 这样就好办了, 大家只需要学会了怎么开汽车, 那么无论是本田, 还是奥迪, 还是大众我们都会开了, 开的时候根本无需关心我开的是哪一类车, 操作手法 (函数调用) 都一样
2, 模仿 interface
在 python 中根本就没有一个叫做 interface 的关键字, 如果非要去模仿接口的概念
可以借助第三方模块: http://pypi.python.org/pypi/zope.interface
也可以使用继承, 其实继承有两种用途
一: 继承基类的方法, 并且做出自己的改变或者扩展(代码重用): 实践中, 继承的这种用途意义并不很大, 甚至常常是有害的. 因为它使得子类与基类出现强耦合.
二: 声明某个子类兼容于某基类, 定义一个接口类 (模仿 java 的 Interface), 接口类中定义了一些接口名(就是函数名) 且并未实现接口的功能, 子类继承接口类, 并且实现接口中的功能
- class Interface:# 定义接口 Interface 类来模仿接口的概念, python 中压根就没有 interface 关键字来定义一个接口.
- def read(self): #定接口函数 read
- pass
- def write(self): #定义接口函数 write
- pass
- class Txt(Interface): #文本, 具体实现 read 和 write
- def read(self):
- print('文本数据的读取方法')
- def write(self):
- print('文本数据的读取方法')
- class Sata(Interface): #磁盘, 具体实现 read 和 write
- def read(self):
- print('硬盘数据的读取方法')
- def write(self):
- print('硬盘数据的读取方法')
- class Process(Interface):
- def read(self):
- print('进程数据的读取方法')
- def write(self):
- print('进程数据的读取方法')
上面的代码只是看起来像接口, 其实并没有起到接口的作用, 子类完全可以不用去实现接口 , 这就用到了抽象类
3, 本节重点 --- 抽象类
3.1, 什么是抽象类
与 java 一样, python 也有抽象类的概念但是同样需要借助模块实现, 抽象类是一个特殊的类, 它的特殊之处在于只能被继承, 不能被实例化
3.2, 为什么要有抽象类
如果说类是从一堆对象中抽取相同的内容而来的, 那么抽象类就是从一堆类中抽取相同的内容而来的, 内容包括数据属性和函数属性.
比如我们有香蕉的类, 有苹果的类, 有桃子的类, 从这些类抽取相同的内容就是水果这个抽象的类, 你吃水果时, 要么是吃一个具体的香蕉, 要么是吃一个具体的桃子...... 你永远无法吃到一个叫做水果的东西.
从设计角度去看, 如果类是从现实对象抽象而来的, 那么抽象类就是基于类抽象而来的.
从实现角度来看, 抽象类与普通类的不同之处在于: 抽象类中只能有抽象方法(没有实现功能), 该类不能被实例化, 只能被继承, 且子类必须实现抽象方法. 这一点与接口有点类似, 但其实是不同的, 即将揭晓答案
4, 在 python 中实现抽象类
- # 一切皆文件
- import abc #利用 abc 模块实现抽象类
- class All_file(metaclass=abc.ABCMeta):
- all_type='file'
- @abc.abstractmethod #定义抽象方法, 无需实现功能
- def read(self):
- '子类必须定义读功能'
- pass
- @abc.abstractmethod #定义抽象方法, 无需实现功能
- def write(self):
- '子类必须定义写功能'
- pass
- # class Txt(All_file):
- # pass
- #
- # t1=Txt() #报错, 子类没有定义抽象方法
- class Txt(All_file): #子类继承抽象类, 但是必须定义 read 和 write 方法
- def read(self):
- print('文本数据的读取方法')
- def write(self):
- print('文本数据的读取方法')
- class Sata(All_file): #子类继承抽象类, 但是必须定义 read 和 write 方法
- def read(self):
- print('硬盘数据的读取方法')
- def write(self):
- print('硬盘数据的读取方法')
- class Process(All_file): #子类继承抽象类, 但是必须定义 read 和 write 方法
- def read(self):
- print('进程数据的读取方法')
- def write(self):
- print('进程数据的读取方法')
- wenbenwenjian=Txt()
- yingpanwenjian=Sata()
- jinchengwenjian=Process()
- # 这样大家都是被归一化了, 也就是一切皆文件的思想
- wenbenwenjian.read()
- yingpanwenjian.write()
- jinchengwenjian.read()
- print(wenbenwenjian.all_type)
- print(yingpanwenjian.all_type)
- print(jinchengwenjian.all_type)
4.1, 抽象类与接口
抽象类的本质还是类, 指的是一组类的相似性, 包括数据属性 (如 all_type) 和函数属性(如 read,write), 而接口只强调函数属性的相似性.
抽象类是一个介于类和接口直接的一个概念, 同时具备类和接口的部分特性, 可以用来实现归一化设计
4.2,abc 模块, Python 对于 ABC 的支持模块, 定义了一个特殊的 metaclass-- ABCMeta 还有一些装饰器 -- @abstractmethod 和 @abstarctproperty .
- import abc
- class A(metaclass=abc.ABCmeta):
- @abc.abstractmethod# 定义抽象方法, 无需实现功能
- def read(self):
- pass
- @abc.abstarctproperty# 定义抽象属性
4.3, 例题
通过定义抽象类, 子类继承抽象类, 把子类规范化, 如果想调用抽象类相同的函数, 就必须和抽象类保持一致, 否则出错
规范子类
- import abc
- class Animal(metaclass=abc.ABCMeta):
- @abc.abstractmethod
- def run(self):
- pass
- @abc.abstractmethod
- def eat(self):
- pass
- class People(Animal):
- def run(self):
- print('people is walking')
- def eat(self):
- print('people is eating')
- class Dog(People):
- def run(self):
- print('dog is walking')
- def eat(self):
- print('dog is eating')
- class Pig(People):
- def run(self):
- print('pig is walking')
- def eat(self):
- print('pig is eating')
- people1 = People()
- dog1 = Dog()
- pig1 = Pig()
- people1.run()
- dog1.run()
- pig1.run()
4.4, 抽象类的说明
不能被实例化, 只能被继承: 上题中 Aminal 是抽象类 , 不能实例化 比如 animal=Aminal()
优点: 规范化子类, 降低使用的复杂度
来源: http://www.bubuko.com/infodetail-2757493.html