类的进阶二

一 归一化设计

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

class Applepay:
    def pay(self,money):
        print('Applepay支付%s'%money)
class Alipay:
    def pay(self,money):
        print('Alipay支付%s'%money)
ap=Applepay()
al=Alipay()
# ap.pay(100)
# a1.pay(100)
def pay(x,money):
    x.pay(money)
pay(ap,100)
pay(al,100)

  这个例子是类的上面一层加了一层函数,函数硬性的调用pay动态属性。简单的实现了归一化。

  

二 abc模块

  python本身不支持抽象类和接口类,要想实现,需要截止abc模块。abc模块是abstract base class(抽象基类) 的缩写。

  ABC(抽象基类),主要定义了基本类和最基本的抽象方法。

  metaclass是“类的类”,即元类。秉承Python“一切皆对象”的理念,Python中的类也是一类对象,metaclass的实例就是类(class)。

  abc模块,python对于abc模块的支持,定义了一个特殊的metaclass——ABCMeta,还有一些装饰器,@abstractmethod,@abstractproperty

  abc.ABCMeta,是一个metaclass,用于在python程序中创建抽象基类。

  metaclass为abc.ABCMeta的抽象基类如果想要声明抽象方法,可以使用abc模块中的装饰器@abstractmethod,如果想声明抽象属性,可以使用装饰器@abstractproperty。

  实例:

from abc import abstractmethod,ABCMeta
class Pay(metaclass=ABCMeta):              #称为接口类,最好不实现具体的方法,推荐多继承。
    @abstractmethod
    def pay(self):
        pass

class Applepay(Pay):
    def pay(self,money):
        print('Applepay支付%s'%money)
class Alipay(Pay):
    def pay(self,money):
        print('Alipay支付%s'%money)
    pass
ap=Applepay()
al=Alipay()

  继承了Pay抽象基类的Applepay,Alipay,必须实现其抽象方法pay。

  PS  

  依赖倒置原则

      A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。

      B.抽象不应该依赖于具体实现,具体实现应该依赖于抽象。
  接口隔离原则
      客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
      使用多个专门的接口比使用单一的总接口要好。
      一个类对另外一个类的依赖性应当是建立在最小的接口上的。
 
三 抽象类
  最好单继承,且可以实现简单的功能。
 
四 钻石继承
  子类,父类,父类的父类。。。
  经典类:深度优先,没有mro方法
  新式类:广度优先,有mro方法。python3中默认都是新式类。
  PS
    MRO(Method Resolution Order):方法解析顺序。
五 多态
  楔子:鸭子类型  
    一只鸟走起来像鸭子、游起泳来像鸭子、叫起来也像鸭子,那它就可以被当做鸭子。也就是说,它不关注对象的类型,而是关注对象具有的行为(方法)。
  继承是多态的基础。所以在调用类的方法时,尽量调用父类的方法,这样所有子类都可以正常实现。
import abc
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def talk(self):
        pass
class People(Animal):
    def talk(self):
        print('说说话')
class Dog(Animal):
    def talk(self):
        print('哼哼哼')
alex=People()
egon=Dog()
# alex.talk()
# egon.talk()

def talk(x):
    x.talk()
talk(alex)
talk(egon)

  talk函数和len函数一样,此时并不需要过多关注传入数据的类型。

  传入的类只要是animal的子类,无需知道传入的确切的类型,都可以放心的调用talk方法,具体调用时talk方法是作用在animal还是dog还是people上,由执行时该对象的确切类型决定,这就是多态真正的威力:只管调用,而不管细节。这也是‘开闭’原则。

  对扩展开放:新增animal子类都可以执行

  对修改封闭:不需要修改talk函数。

六   object与type

class A:
    pass
print(A.__bases__)
print(type(A))
print(type(list))

  输出:

(<class 'object'>,)
<class 'type'>
<class 'type'>

  object是所有类的基类。type是所有类的类型。

  元类——>metaclass

import abc
class A(metaclass=abc.ABCMeta):
    pass
print(A.__bases__)
print(type(A))

  输出:

(<class 'object'>,)
<class 'abc.ABCMeta'>

 

posted @ 2017-09-19 15:37  骑者赶路  阅读(227)  评论(0编辑  收藏  举报