面向对象三大特性——继承高阶(接口和抽象类)

一、接口(Interface)

  在C++、JAVA等程序开发时,往往会利用到接口。接口其实就是:自己提供给使用者来调用自己功能的方式\方法\入口。

=================第一部分: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");
    } 
}

=================第四部分:Tester03.java
package com.oo.demo;

public class Tester03 {
    public static void main(String[] args) {
        System.out.println("===This is a person==="); 
        IAnimal person = new Person2();
        person.eat();
        person.run();
        person.sleep();
        person.speak();

        System.out.println("\n===This is a pig===");
        IAnimal pig = new Pig();
        pig.eat();
        pig.run();
        pig.sleep();
        pig.speak();
    } 
}

 java中的interface
java中interface

1、使用接口的好处

  接口提取了一群类共同的函数,可以把接口当做一个函数的集合。然后让子类去实现接口中的函数。这样做得好处也就是实现了归一化。

二、归一化

  归一化:只要是基于同一个接口实现的类,那么这些类产生的对象在使用时,从用法来说是一样的。

1、归一化的好处

  1)让使用者无需关心对象的类,只需要知道这些对象都具备某些功能即可,降低使用难度。

  2)让高层的外部使用者可以不加区分地处理所有接口兼容的对象集合。

1、就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,对底层设计者,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。

2、再比如:我们有一个汽车接口,里面定义了汽车所有的功能,然后由本田汽车的类,奥迪汽车的类,大众汽车的类,他们都实现了汽车接口,这样就好办了,大家只需要学会了怎么开汽车,那么无论是本田,还是奥迪,还是大众我们都会开了,开的时候根本无需关心我开的是哪一类车,操作手法(函数调用)都一样
接口兼容处理例子

三、python中实现接口

  在python中并没有interface关键字,如果想去模仿接口概念,有两种方法:

方法一:借助第三方模块 http://pypi.python.org/pypi/zope.interface

方法二:使用继承。

1、继承的两种用途

  1)继承基类的方法,并做出自己的改变或扩展(代码重用)。

  实际这种用法意义不大,甚至往往是有害的,因为它会使得子类和基类出现强耦合

  2)声明某个子类兼容于某基类,定义一个接口类,接口类中定义一些接口名(函数名)且并未实现接口功能,子类继承接口类,并实现接口的功能。又称为接口继承

# 正常实现调用
class Applepay:
    def pay(self,money):
        print('apple pay 支付了%s' %money)

class Alipay:
    def pay(self,money):
        print('支付宝  支付了%s' %money)

def payment(pay_obj,money):  #实例化的另一种调用,这个方法让实例化的时候按照payment调用:就像下面的payment(apple1,200)
        pay_obj.pay(money)

apple1 = Applepay()
# apple1.pay(200)
payment(apple1,200)
"""
apple pay 支付了200
"""
正常实现调用
# 2.有时候写的时候会把方法写错,自己定义一个主动报错
# 接口初成:手动报异常:NotImplementedError来解决开发中遇到的问题
class Payment:
    def pay(self):
        raise NotImplementedError  #主动让程序报错

class Wechatpay(Payment): #微信支付
    def pay(self,money):
        print('微信支付了%s元',money)

class QQchatpay(Payment): #QQ支付
    def fuqian(self,money):
        print('QQ支付了%s元',money)

p = Wechatpay()
p.pay(200)   #不报错  # 微信支付了%s元 200
q = QQchatpay()  
q.pay()  #报错
主动报错
# 3.借用abc模块来实现接口
#接口类(就是为了提供标准,约束后面的子类)
from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self,money):
        pass

class Wechatpay(Payment):
    def fuqian(self,money):
        '''实现了pay的功能,但是方法名字不一样'''
        print('微信支付了%s元'%money)

class Alipay:
    def pay(self,money):
        print('支付宝  支付了%s' %money)

# p = Wechatpay() #报错了(因为上面定义了一个接口类,接口类里面
# 定义了一个pay方法,而在下面的Wechatpay方法里没有pay方法,不能
# 调用,在接口类里面约束一下,接口类里的pay方法里面不能写其他,直接pass)
a = Alipay()
a.pay(200)
"""
支付宝  支付了200
"""
# p = Payment() #接口类不能被实例化
abc模块实现接口

  由上面的例子可以归结,接口也就是做约束,让下面的类的方法都按照接口类中给出的方法去定义。如果接口类里有的方法类里面没有,则这个类不能被实例化。而abc模块的使用,则说明了接口和抽象类的关联性。

四、抽象类

1、抽象类概念

  抽象类往往用来表征对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

2、抽象类特点

  抽象类与普通类的特殊之处就是只能被继承抽象类是不完整的,它只能用作基类),不能被实例化

3、抽象类用处

  在面向对象方法中,抽象类主要用来进行类型隐藏和充当全局变量的角色。降低使用者的使用复杂度,统一标准。

4、抽象类的实现

  python的abc模块中定义了抽象类的metaclass类ABCMeta,以及抽象方法装饰器abstractmethod, abstractclassmethod, abstractstaticmethod,抽象property装饰器abstractproperty等。可以基于这些工具来实现自己的抽象类。

import abc    #利用abc模块实现抽象类

class Animal(metaclass=abc.ABCMeta):  # 类似接口,只定义规范,不实现具体的代码
    @abc.abstractclassmethod
    def run(self):
        pass

    @abc.abstractclassmethod
    def eat(self):
        pass

# 尝试实例化抽象类:结果失败
# animal = Animal()
# TypeError: Can't instantiate abstract class Animal with abstract methods eat, run

class People(Animal):
    def run(self):  # 不符合规范,不允许实例化
        print('people is walking')

    def eat(self):
        print('people is eating')

class Pig(Animal):
    def run(self):
        print('Pig is running')

    def eat(self):
        print('Pig is eating')

class Dog(Animal):
    def run(self):
        print('Dog is zouing')

    def eat(self):
        print('Dog is eating')

peo1 = People()
pig1 = Pig()
Dog1 = Dog()

peo1.eat()
pig1.eat()
Dog1.run()
"""
people is eating
Pig is eating
Dog is zouing
"""
抽象类实现
#一切皆文件
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)
一切皆文件

五、抽象类与接口

  抽象类表示该类中可能已经有一些方法的具体定义,但是接口就仅仅只能定义各个方法的界面(方法名,参数列表,返回类型),并不关心具体细节。 

  抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

  抽象类是一个介于类和接口之间的一个概念,同时具备类和接口的部分特性,可以用以实现归一化设计。

1、抽象类和接口相同点

  1、不能实例化;

  2、包含未实现的方法声明;

  3、派生类必须实现未实现的方法,抽象类是抽象方法,接口则是所有成员(不仅是方法包括其他成员)

2、不同点

  1、类可以实现无限个接口,但仅能从一个抽象(或任何其他类型)类继承,从抽象类派生的类仍可实现接口,从而得出接口是用来解决多重继承问题的。

  2、抽象类当中可以存在非抽象的方法,可接口不能。

  3、抽象类中的成员变量可以被不同的修饰符来修饰,可接口中的成员变量默认的都是静态常量(static final)。

  4、抽象类是对象的抽象,然而接口是一种行为规范。

posted @ 2018-04-24 10:45  休耕  阅读(936)  评论(0编辑  收藏  举报