设计模式-结构型模式

设计模式-结构型模式

适配器模式

适配器模式也叫 封装器模式、Wrapper、Adapter

假如你正在开发一个接口。接口要求返回一定的数据给前端。

在开发过程中原先只需要在orm中查询。 新需求需要程序中整合一个第三方api。 但是遇到了一个问题,接口只返回兼容 JSON 格式的数据。

可以去修改第三方api源码 但是坏情况 并没有源码

所以说需要通过适配器去整合两部分结构

适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至察觉不到适配器的存在。 例如, 你可以使用一个将所有数据转换为英制单位 (如英尺和英里) 的适配器封装运行于米和千米单位制中的对象。

import  json

class Outer(object):
    """用于处理接口请求

    Args:
        object ([type]): [description]
    """
    @classmethod
    def query(self):
        return "get something"


class myfun(object):
    """系统内部的查询接口

    Args:
        object ([type]): [description]
    """
    def __init__(self):
        pass

    def setinfo():
        """写入数据库
        """
        pass

    def serialize(self, data):
        json.loads(data)        
        return data


class Adapter(object):
    """通过适配器整合两个功能

    Args:
        object ([type]): [description]
    """

    def query(self):
        return Outer.query()

    def serialize(self):
        my = myfun()
        return my.serialize("[1,2]")

#在实现功能的同时并没有对 两个类进行内部的修改
def client_code():
    ap = Adapter()
    print(ap.query())
    print(ap.serialize())

client_code()

组合模式

#抽象一个组织类
class Component:
    def __init__(self,name):
        self.name=name

    def add(self,comp):
        pass
    def remove(slef,comp):
        pass
    def display(self,depth):
        pass

#叶子节点
class Leaf(Component):
    def add(self):
        print('不能添加子节点')
    def remove(self):
        print('不能删除子节点')
    def display(self,depth):
        strtemp=''
        for i in range(depth):
            strtemp +='---'
        print(strtemp+self.name)

#枝节点
class Composite(Component):
    def __init__(self,name):
        self.name=name
        self.children=[]
    def add(self,comp):
        self.children.append(comp)
    def remove(self,comp):
        self.children.remove(comp)
    def display(self,depth):
        strtemp=''
        for i in range(depth):
            strtemp += '---'
        print(strtemp+self.name)
        for comp in self.children:
            comp.display(depth+2)

if __name__=='__main__':
    root=Composite('xx科技')

    root.add(Leaf('董事长'))
    root.add(Leaf('人事'))
    root.add(Leaf('财务'))
    root.add(Leaf('董事长助理'))
    comp1a=Composite('开发中心')
    comp1b=Composite('产品中心')
    root.add(comp1a)
    root.add(comp1b)
    comp1a.add(Leaf('xx'))
    comp1a.add(Leaf('xxx'))
    comp1a.add(Leaf('xxx'))
    comp1a.add(Leaf('xx'))
    comp1a.add(Leaf('xx'))
    comp2a=Composite('实习生部门')
    comp1a.add(comp2a)

    comp1b.add(Leaf('xx'))
    comp1b.add(Leaf('xxx'))



    root.display(1)
    comp1a.display(1)

装饰模式

python 中的装饰器

#函数可以作为参数传递的语言,可以使用装饰器
#装饰器的作用就是为已经存在的对象添加额外的功能。


def w1(func):
  def inner():
    print('...验证权限...')
    func()

  return inner


@w1
def f1():
  print('f1 called')


@w1
def f2():
  print('f2 called')

f1()
f2()

#...验证权限...
#f1 called
#...验证权限...
#f2 called

通过装饰器。将函数f1,f2作为参数传递给w1,w1在执行完成inner内容后执行func()的方法

装饰器的使用场景

比如一个原始项目的一个函数在许多代码中都有使用。新需求要求有权限才可以调用。类似这样的场景我们就可以使用装饰器方法

以往的解决方案

  • 让调用方也在调用的时候,先主动进行权限验证
  • 让原函数中,首先进行权限认证,然后再进行真正的函数操作

以往的解决方案的问题
– 方案一,将本不该暴露给外层的权限认证,暴露在使用方面前,需要验证的方法都需要修改
– 方案二,看似看行,可是函数内部的方法也需要逐个修改

wraps

Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),而我们不希望原来函数的属性被覆盖。

from functools import wraps   
def my_decorator(func):
    def wrapper(*args, **kwargs):
        '''decorator'''
        print('Calling decorated function...')
        return func(*args, **kwargs)
    return wrapper  

@my_decorator 
def example():
    """Docstring""" 
    print('Called example function')
print(example.__name__, example.__doc__)
输出:
('wrapper', 'decorator')
[Finished in 0.2s]
#!/usr/bin/env python3
from functools import wraps   
def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        '''decorator'''
        print('Calling decorated function...')
        return func(*args, **kwargs)
    return wrapper  

@my_decorator 
def example():
    """Docstring""" 
    print('Called example function')
print(example.__name__, example.__doc__)
#输出:
#s('wrapper', 'decorator')

享元模式

缓存、Cache、Flyweight
在一些需要大量创建对象的业务场景中。如加载大量图片。但是其中有一些共有属性其实都相同。这时候就造成不必要的内存浪费。

#!/usr/bin/env python3
#享元模式

class Color(object):
    _instances = dict()
    def __new__(cls, *args, **kargs):
        return cls._instances.setdefault(
                    (cls, args, tuple(kargs.items())),
                    super(type(cls), cls).__new__(cls, *args, **kargs))

class Red(Color):
    def __init__(self):
        self.R = 255
        self.G = 0
        self.B = 0

class Blue(Color):
    def __init__(self):
        self.R = 0
        self.G = 0
        self.B = 255

class Green(Color):

    def __init__(self):
        self.R = 0
        self.G = 128
        self.B = 0


class ball(object):
    def __init__(self):
        self.a ="s"
        self.b = "b"
        self.colorobj = Red()


ball1 = ball()
ball2 =ball()

assert ball1.colorobj is ball2.colorobj

代理模式

代理模式就是 为了保护原本类 代理抽象一个实现他功能的接口。比如flaks 中的 localpoxy

以全局对象request为例,其中函数_lookup_req_object的作用是取当前线程/协程中LocalStack对象栈顶对象的某个属性,这里的partial(_lookup_req_object, ‘request’)实际返回了一个callable对象,这个callable对象每次被调用都会返回LocalStack栈顶的名为request的属性,实际就是当前要处理的request对象。与LocalProxy配合使用,就使得这个全局request对象总是指向当前线程/协程栈顶的request对象,也就是当前要处理的request对象。

class LocalProxy(object):
    """
    Example usage::

        from werkzeug.local import Local
        l = Local()

        # these are proxies
        request = l('request')
        user = l('user')


        from werkzeug.local import LocalStack
        _response_local = LocalStack()

        # this is a proxy
        response = _response_local()

    Whenever something is bound to l.user / l.request the proxy objects
    will forward all operations.  If no object is bound a :exc:`RuntimeError`
    will be raised.

    To create proxies to :class:`Local` or :class:`LocalStack` objects,
    call the object as shown above.  If you want to have a proxy to an
    object looked up by a function, you can (as of Werkzeug 0.6.1) pass
    a function to the :class:`LocalProxy` constructor::

        session = LocalProxy(lambda: get_current_request().session)

    .. versionchanged:: 0.6.1
       The class can be instantiated with a callable as well now.
    """

    __slots__ = ("__local", "__dict__", "__name__", "__wrapped__")

    def __init__(self, local, name=None):
        object.__setattr__(self, "_LocalProxy__local", local)
        object.__setattr__(self, "__name__", name)
        if callable(local) and not hasattr(local, "__release_local__"):
            # "local" is a callable that is not an instance of Local or
            # LocalManager: mark it as a wrapped function.
            object.__setattr__(self, "__wrapped__", local)

    def _get_current_object(self):
        """Return the current object.  This is useful if you want the real
        object behind the proxy at a time for performance reasons or because
        you want to pass the object into a different context.
        """
        # 由于所有Local或LocalStack对象都有__release_local__ method, 所以如果没有该属性就表明self.__local为callable对象
        if not hasattr(self.__local, "__release_local__"):
            return self.__local()
        # 此处self.__local为Local或LocalStack对象
        try:
            return getattr(self.__local, self.__name__)
        except AttributeError:
            raise RuntimeError("no object bound to %s" % self.__name__)

    @property
    def __dict__(self):
        try:
            return self._get_current_object().__dict__
        except RuntimeError:
            raise AttributeError("__dict__")

    def __repr__(self):
        try:
            obj = self._get_current_object()
        except RuntimeError:
            return "<%s unbound>" % self.__class__.__name__
        return repr(obj)

    def __bool__(self):
        try:
            return bool(self._get_current_object())
        except RuntimeError:
            return False

    def __dir__(self):
        try:
            return dir(self._get_current_object())
        except RuntimeError:
            return []

    def __getattr__(self, name):
        if name == "__members__":
            return dir(self._get_current_object())
        return getattr(self._get_current_object(), name)

    def __setitem__(self, key, value):
        self._get_current_object()[key] = value

    def __delitem__(self, key):
        del self._get_current_object()[key]
_request_ctx_err_msg = '''\
Working outside of request context.

This typically means that you attempted to use functionality that needed
an active HTTP request.  Consult the documentation on testing for
information about how to avoid this problem.\
'''
_app_ctx_err_msg = '''\
Working outside of application context.

This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context().  See the
documentation for more information.\
'''


def _lookup_req_object(name):
    top = _request_ctx_stack.top
    if top is None:
        raise RuntimeError(_request_ctx_err_msg)
    return getattr(top, name)


def _lookup_app_object(name):
    top = _app_ctx_stack.top
    if top is None:
        raise RuntimeError(_app_ctx_err_msg)
    return getattr(top, name)


def _find_app():
    top = _app_ctx_stack.top
    if top is None:
        raise RuntimeError(_app_ctx_err_msg)
    return top.app


# context locals
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
g = LocalProxy(partial(_lookup_app_object, 'g'))
from flask import Flask
from flask import request

app = Flask(__name__)
app.debug = True

@app.route('/args', methods=["get"])
def getargs():
    #LocalProxy 的一些内置方法就可以调用
    print(request.__dict__)
    form = request.args
    return "hellow"


if __name__ == '__main__':
    app.run("0.0.0.0", 8081)

桥接模式模式

外观模式

发表评论

电子邮件地址不会被公开。 必填项已用*标注