编程范式:面向对象、创建型设计模式

《Python服务端工程师面试宝典-PegasusWang》学习笔记,第三章:面向对象基础、装饰器、创建型模式、结构性模式、行为型模式和函数式编程。
335阅读 · 2020-5-26 15:35发布

3.1 面向对象基础

什么是面向对象编程?

  • Object Oriented Programming(OOP):把对象作为基类单元,把对象抽象成类(class),包含成员和方法。
  • 数据封装、继承、多台。
  • Python中使用类来实现面向对象编程。类示例:

    class Person(object):  # 声明类
          def __init__(self,name,age):  # 初始化方法
              self.name = name  # 成员、属性
              self.age = age
              self_sex = 1  # 带有_的表示私有属性
    
          def print_name(self):  # 类方法
              print('my name is {}'.format(self.name))
    
          def __len(self):  # 魔术方法
              pass
    

什么是组合与继承?

  • 组合是使用其他的类实例作为自己的一个属性(Has-a关系)。
  • 子类继承父类的属性和方法(IS-a关系)。
  • 建议优先使用组合保持代码简单。

什么是类变量和实例变量?

  • 类变量由所有实例共享。
  • 实例变量由实例单独享有,不同实例之间不影响。
  • 当我们需要在不同实例之间共享变量的时候使用类变量。示例:

    class Preson:
          Country = 'china'  # 类变量
    
          def __init__(self,name):
              self.name = name  # 实例变量
    
          def print_name(self):
              print(self.name)
    

classmethod和staticmethod区别

  • 他们都经常用作类方法的装饰器。
  • 都可以通过Class.method()的方式使用。
  • classmethod第一个参数是class,可以应用类变量。
  • staticmethod和普通函数一样,只不过它放在类中。

什么是元类?使用场景是什么?

  • 元类(Meta Class)是创建类的类。
  • 元类允许我们控制类的生成,比如修改类的属性等。
  • 使用type来定义元类。示例:

    class x:
          a = 1
      # 等价于如下写法
      x = type('x',(object,),dict(a=1))
    
  • 元类最常见的一个使用场景就是ORM框架。

  • 使用元类使类的属性名称都改为小写。示例:

    # 元类都继承自type
      class LowercaseMeta(type):
          def __new__(msc,name,bases,attrs):
              lower_attrs = {}
              for k,v in attrs.items():
                  if not k.startswith('__'):
                      lower_attrs[k.lower()] = v
                  else:
                      lower_attrs[k] = v
              return type.__new__(msc,name,bases,lower_attrs)
    
      class LowercaseClass(metaclass=LowercaseMeta):
          BAR = True
    
          def HELLO(self):
              print('hello')
    
      print(dir(LowercaseClass))
      # 输出
      #['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'hello']
    

3.2 装饰器

什么是装饰器?

  • Python中一切皆对象,函数也可以当做参数传递。
  • 装饰器是接受函数作为参数,添加功能后返回一个新函数的函数。
  • Python中通过@使用装饰器(@为语法糖)。函数装饰器示例:

    import time
      def log_time(func):
          def _log(*args,**kwargs):
              beg = time.time()
              res = func(*args,**kwargs)
              print('use time:{}'.format(time.time()-beg))
              return res
          return _log
    
      @log_time
      def mysleep():
          time.sleep(1)
    
      mysleep()
    

如何使用类编写装饰器?

  • 和函数装饰器相似。示例:

    import time
    
      class LogTime:
          def __call__(self,func):
              def _log(*args,**kwargs):
                  beg = time.time()
                  res = func(*args,**kwargs)
                  print(time.time()-beg)
                  return res
              return _log
    
      @LogTime()  #需要初始化装饰类的实例
      def mysleep():
          time.sleep(1)
    
      mysleep()
    

如何给装饰器增加参数?

  • 使用类装饰器,通过类的初始化来传递参数。示例:

    import time
    
      class LogTime:
          def __init__(self,use_int=False):
              self.use_int = use_int
    
          def __call__(self,func):
              def _log(*args,**kwargs):
                  beg = time.time()
                  res = func(*args,**kwargs)
                  if self.use_int:
                      print(time.time()-beg)
                  else:
                      print(int(time.time()-beg))
                  return res
              return _log
    
      @LogTime(False)
      def mysleep():
          time.sleep(1)
    
      mysleep()
    

3.3 设计模式:创建型模式

常见创建型设计模式

  • 工厂模式(Factory):解决对象创建问题。
  • 构造模式(Builder):控制复杂对象的创建。
  • 原型模式(Prototype):通过原型的克隆创建新的实例。
  • 单例(Borg/Singleton):一个类只能创建同一个对象。
  • 对象池模式(Pool):预先分配同一类型的一组实例。
  • 惰性计算模式(Lazy Evaluation):延迟计算(pythond的property,访问属性的时候才做计算操作)

什么是工厂模式?

  • 解决对象创建问题。
  • 解耦对象的创建和使用。
  • 包括工厂方法和抽象工厂。
  • 工厂模式代码示例:
class DogToy:
    def speak(self):
        print('wangwang')

class CatToy:
    def speak(self):
        print('miaomiao')

def toy_factory(toy_type):
    if toy_type == 'dog':
        return DogToy()
    elif toy_type == 'cat':
        return CatToy()

toy_factory('cat').speak()

什么是构造模式?

  • 用来控制复杂对象的构造。
  • 将创建和表示分离。即将一个复杂对象拆分为每个组件,分别先创建组件再完成整个构造。示例代码:

    class Computer:
    
          def __init__(self, serial_number):
              self.serial = serial_number
              self.memory = None  # 单位为GB
              self.hdd = None     # 单位为GB
              self.gpu = None
    
          def __str__(self):
              info = ('Memory: {}GB'.format(self.memory),
                      'Hard Disk: {}GB'.format(self.hdd),
                      'Graphics Card: {}'.format(self.gpu))
              return '\n'.join(info)
    
      class ComputerBuilder:
    
          def __init__(self):
               self.computer = Computer('AG23385193')
    
          def configure_momory(self, amount):
              self.computer.memory = amount
    
          def configure_hdd(self, amount):
              self.computer.hdd = amount
    
          def configure_gpu(self, gpu_model):
              self.computer.gpu = gpu_model
    
      class HardwareEngineer:
    
          def __init__(self):
              self.builder = None
    
          def construct_computer(self, memory, hdd, gpu):
              self.builder = ComputerBuilder()
              [step for step in (self.builder.configure_momory(memory),
                                 self.builder.configure_hdd(hdd),
                                 self.builder.configure_gpu(gpu))]
    
          @property
          def computer(self):
              return self.builder.computer
    
      engineer = HardwareEngineer()
      engineer.construct_computer(hdd=500, memory=8, gpu='GeForce GTX 650 Ti')
      computer = engineer.computer
      print(computer)
    

什么是原型模式?

  • 通过克隆原型来创建新的实例。
  • 可以使用相同的原型,通过修改部分属性来创建新的实例。
  • 使用场景:对于一些创建实例开销比较高的地方可以使用原型模式。

什么是单例模式?

  • 一个类创建出来的对象都是同一个。
  • Python的模块就是单例的,只会导入一次。
  • 使用共享同一实例的方式来创建单例模式。示例:

    class Singleton:
          def __new__(cls,*args,**kwargs):
              if not hasattr(cls, '_instance'):
                  _instance = super().__new__(cls,*args,**kwargs)
                  cls._instance = _instance
              return cls._instance
    
      class MyClass(Singleton):
          pass
    
      c1 = MyClass()
      c2 = MyClass()
      print(c1 is c2)
    

3.4 设计模式:结构型模式

常见结构型设计模式

  • 装饰器模式(Decorator):无需子类化扩展对象功能。
  • 代理模式(Proxy):把一个对象的操作代理到另一个对象。
  • 适配器模式(Adapter):通过一个间接层适配统一接口。
  • 外观模式(Facade):简化复杂对象的访问问题。
  • 享元模式(Flyweight):通过对象复用(池)改善资源利用,比如连接池。
  • Model-View-Controlle(MVC):解耦展示逻辑和业务逻辑。

什么是代理模式?

  • 把一个对象的操作代理到另一个对象。
  • 例如实现Stack/Queue时可以操作代理到deque。
  • 通常是has-a组合关系。
  • 代理模式示例:

    from collections import deque
      class stack(object):
          def __init__(self):
              self._deque = deque()
    
          def push(self,value):
              return self._deque.append(value)
    
          def pop(self):
              return self._deque.pop()
    
          def empty(self):
              return len(self._deque) == 0
    

什么是适配器模式?

  • 把不同对象的接口适配到同一个接口。
  • 例如多功能充电头,可以给不同电器充电。
  • 需要给不同对象统一接口时可以使用适配器模式。
  • 适配器模式代码示例:

    class Dog(object):
          def __init__(self):
              self.name = "Dog"
    
          def bark(self):
              return "woof!"
    
      class Cat(object):
          def __init__(self):
              self.name = "Cat"
    
          def meow(self):
              return "meow!"
    
      class Adapter:
          def __init__(self,obj,**adapted_methods):
              self.obj = obj
              self.__dict__.update(adapted_methods)
    
          def __getattr__(self,attr):
              return getattr(self.obj,attr)
    
      objects = []
      dog = Dog()
      objects.append(Adapter(dog,make_noise=dog.bark))
      cat = Cat()
      objects.append(Adapter(cat,make_noise=cat.meow))
      for obj in objects:
          print("A {0} goe {1}".format(obj.name,obj.make_noise()))
    

3.5 设计模式:行为型模式

常见行为型设计模式

  • 迭代器模式(Iterator):通过统一的接口迭代对象。
  • 观察者模式(Observer):对象发生改变的时候,观察者执行相应动作(发布订阅)。
  • 策略模式(Strategy):针对不同规模输入使用不同的策略。

什么是迭代器模式?

  • Python内置对迭代器模式的支持。
  • 可以使用for遍历各种Iterable的数据类型。
  • Python里可以实现nextiter实现迭代器。
  • 迭代器代码示例:

    from collections import deque
      class stack(object):
          def __init__(self):
              self._deque = deque()
    
          def push(self,value):
              return self._deque.append(value)
    
          def pop(self):
              return self._deque.pop()
    
          def empty(self):
              return len(self._deque) == 0
    
          def __iter__(self):
              res = []
              for i in self._deque:
                  res.append(i)
              for i in reversed(res):  #后进先出,使用reversed反转list
                  yield i
    
      a = stack()
      a.push('aaa')
      a.push('bbb')
      for i in a:
          print(i)
    

什么是观察者模式?

  • 发布订阅是一种最常用的实现方式。
  • 发布订阅用于解耦逻辑。
  • 可以通过回调等方式实现,当发生事件时,调用响应的回调函数。
  • 观察者模式代码示例(发布者中加入一堆观察者,发生相应事件的时候就会回调所有观察者的自定义回调函数):

    class Publisher:
          def __init__(self):
              self.observers = []  #观察者
    
          def add(self,observer):
              if observer not in self.observers:
                  self.observers.append(observer)
              else:
                  print('已经存在:{}').format(observer)
    
          def remove(self,observer):  #移除观察者
              try:
                  self.observers.remove(observer)
              except ValueError:
                  print('删除失败:{}').format(observer)
    
          def notify(self):  #调用观察者回调
              [o.notify_by(self) for o in self.observers]
    
      class Formatter(Publisher):  # 继承自发布者
          def __init__(self,name):
              super().__init__()
              self.name = name
              self._data = 0
    
          @property
          def data(self):
              return self._data
    
          @data.setter
          def data(self,new_value):
              self._data = int(new_value)
              self.notify()
    
      class BinaryFormatter:  # 订阅者
          def notify_by(self,publisher):
              print("{}:'{}' has now bin data {}".format(type(self).__name__,publisher.name,bin(publisher.data)))
    
      df = Formatter('formatter')  # 发布者
      bf = BinaryFormatter()  # 订阅者
      df.add(bf)  # 添加订阅者
      df.data = 3
    

什么是策略模式?

  • 根据不同的输入采用不同的策略。
  • 比如买东西超过10个打八折,超过20个打七折。
  • 对外暴露统一接口,内部采用不同的策略逻辑。

3.6 函数式编程

函数式编程的特性

  • 把电脑的运算视作数学上的函数计算(lambda演算)
  • 高阶函数:map/reduce/filter

什么是闭包?

  • 闭包(Closure),绑定了外部作用域的变量的函数。
  • 即使程序离开外部作用域,如果闭包仍然可见,绑定变量不会销毁。
  • 每次运行外部函数都会重新创建闭包。
  • 闭包代码示例:

    from functools import wraps
    
      def cache(func):  # 即使该外部函数运行结束,闭包还是应用了外部变量,那么变量依然存在。
          store = {}  # 外部作用域的变量
    
          @wraps(func)
          def _(n):  # 闭包
              if n in store:
                  return store[n]
              else:
                  res = func(n)
                  store[n] = res
                  return res
          return _
    
      @cache
      def f(n):
          if n <= 1:
              return 1
          return f(n-1) +f (n-2)