装饰器模式在python java C++中的应用 相同点和区别

Python装饰器

装饰器的应用,主要有一下几类, 但是目标基本上是一致的都是为了解决同一类问题,需要经过同一类的解决方案。

  • 给函数调用做缓存
  • profiler的例子
  • 注册回调函数
  • 给函数打日志
  • 一个mysql的decorator
  • 线程异步
  • 其他

flask应用的login_required

针对不同的接口,某些需要进行token验证,某些不需要。 需要验证的哪些接口,要进行验证的步骤和方法是一致的,所以希望实现如下功能就可以了



@bp.route('/create_order', methods=['POST'])
@login_required
def create_order():
    pass


@bp.route('/list_users', methods=['POST'])
@login_required
def create_order():
    pass


@bp.route('/stations', methods=['POST'])
def create_order():
    pass

#装饰器的写法如下
def login_required(func):
    @wraps(func) # 假如没有这个去掉副作用的方法的话,视图函数都成一样的了,flask应用就会出现错误了。
    def wrapper(*args, **kwargs):
        res = Auth.identify(Auth, request)
        if res["code"] != 200:
            return jsonify(res)
        return func(*args, **kwargs)
    return wrapper

给函数调用做缓存

通过此方法,把这个递归从二叉树式的递归成了线性的递归。

from functools import wraps

def memo(fn):
    cache = {}
    miss = object()

    @wraps(fn)
    def wrapper(*args):
        result = cache.get(args, miss)
        if result is miss:
            result = fn(*args)
            cache[args] = result
        return result
    return wrapper

@memo
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)
import time
print "start", time.time()
print fib(100)
print "done", time.time()

注册回调函数

class MyApp():
    def __init__(self):
        self.func_map = {}

    def register(self, name):
        def func_wrapper(func):
            self.func_map[name] = func
            return func
        return func_wrapper

    def call_method(self, name=None):
        func = self.func_map.get(name, None)
        if func is None:
            raise Exception("No function registered against - " + str(name))
        return func()

app = MyApp()

@app.register('/')
def main_page_func():
    return "This is the main page."

@app.register('/next_page')
def next_page_func():
    return "This is the next page."

print app.call_method('/')
print app.call_method('/next_page')

给函数打日志



import inspect

def advance_logger(loglevel):

    def get_line_number():
        return inspect.currentframe().f_back.f_back.f_lineno

    def _basic_log(fn, result, *args, **kwargs):
        print "function   = " + fn.__name__,
        print "    arguments = {0} {1}".format(args, kwargs)
        print "    return    = {0}".format(result)

    def info_log_decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            result = fn(*args, **kwargs)
            _basic_log(fn, result, args, kwargs)
        return wrapper

    def debug_log_decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            ts = time.time()
            result = fn(*args, **kwargs)
            te = time.time()
            _basic_log(fn, result, args, kwargs)
            print "    time      = %.6f sec" % (te-ts)
            print "    called_from_line : " + str(get_line_number())
        return wrapper

    if loglevel is "debug":
        return debug_log_decorator
    else:
        return info_log_decorator

一个mysql的decorator

能够方便的解决sql处理的问题

import umysql
from functools import wraps

class Configuraion:
    def __init__(self, env):
        if env == "Prod":
            self.host    = "coolshell.cn"
            self.port    = 3306
            self.db      = "coolshell"
            self.user    = "coolshell"
            self.passwd  = "fuckgfw"
        elif env == "Test":
            self.host   = 'localhost'
            self.port   = 3300
            self.user   = 'coolshell'
            self.db     = 'coolshell'
            self.passwd = 'fuckgfw'

def mysql(sql):

    _conf = Configuraion(env="Prod")

    def on_sql_error(err):
        print err
        sys.exit(-1)

    def handle_sql_result(rs):
        if rs.rows > 0:
            fieldnames = [f[0] for f in rs.fields]
            return [dict(zip(fieldnames, r)) for r in rs.rows]
        else:
            return []

    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            mysqlconn = umysql.Connection()
            mysqlconn.settimeout(5)
            mysqlconn.connect(_conf.host, _conf.port, _conf.user, \
                              _conf.passwd, _conf.db, True, 'utf8')
            try:
                rs = mysqlconn.query(sql, {})
            except umysql.Error as e:
                on_sql_error(e)

            data = handle_sql_result(rs)
            kwargs["data"] = data
            result = fn(*args, **kwargs)
            mysqlconn.close()
            return result
        return wrapper

    return decorator

@mysql(sql = "select * from coolshell" )
def get_coolshell(data):
    ... ...
    ... ..

异步处理

from threading import Thread
from functools import wraps

def async(func):
    @wraps(func)
    def async_func(*args, **kwargs):
        func_hl = Thread(target = func, args = args, kwargs = kwargs)
        func_hl.start()
        return func_hl

    return async_func

if __name__ == '__main__':
    from time import sleep

    @async
    def print_somedata():
        print 'starting print_somedata'
        sleep(2)
        print 'print_somedata: 2 sec passed'
        sleep(2)
        print 'print_somedata: 2 sec passed'
        sleep(2)
        print 'finished print_somedata'

    def main():
        print_somedata()
        print 'back in main'
        print_somedata()
        print 'back in main'

    main()


参考文章

https://coolshell.cn/articles/11265.html

http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python

https://www.thecodeship.com/patterns/guide-to-python-function-decorators/

Python装饰器模式

关于作用域

    装饰器模式,重点在于装饰。装饰的核心仍旧是被装饰对象; Python的作用域体现在LEGB:
  • L: local函数内部
  • E: enclosing 函数内部和内置函数之间
  • G: global全局性质,有命名空间的限制
  • B: build-in内置函数,由python机器是管理

关于闭包

def func1():
    print 'func1 is running'
    def in_func1():
        print 'in_func1 is running'
        return in_func1
    print 'over'
    return in_func1()

func1 is running
over
in_func1 is running

#闭包函数的实例
# outer是外部函数 a和b都是外函数的临时变量
def outer( a ):
    b = 10
    # inner是内函数
    def inner():
        #在内函数中 用到了外函数的临时变量
        print(a+b)
    # 外函数的返回值是内函数的引用
    return inner

if __name__ == '__main__':
    # 在这里我们调用外函数传入参数5
    #此时外函数两个临时变量 a是5 b是10 ,并创建了内函数,然后把内函数的引用返回存给了demo
    # 外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数
    demo = outer(5)
    # 我们调用内部函数,看一看内部函数是不是能使用外部函数的临时变量
    # demo存了外函数的返回值,也就是inner函数的引用,这里相当于执行inner函数
    demo() # 15

    demo2 = outer(7)
    demo2()#17

关于装饰器

def bar():
    print 'Bar'

@bar
def foo():
    print "foo"
# 其等价于:
def foo():
    print "foo"
foo = bar(foo)

先执行@对象,也就是一个函数。其返回值就是一个内置函数, 只不过这个内置函数是得到了装饰的被装饰对象(这里是foo函数),我们可以理解为:

装饰器,其本身接收一个函数对象作为参数,然后做一些工作后,返回接收的参数,供外界调用。
import time

def function_performance_statistics(trace_this=True):
    if trace_this:
       def performace_statistics_delegate(func):
            def counter(*args, **kwargs):
                start = time.clock()
                func(*args, **kwargs)
                end =time.clock()
                print 'used time: %d' % (end - start, )
            return counter
    else:
       def performace_statistics_delegate(func):
            return func
    return performace_statistics_delegate

@function_performance_statistics(True)
def add(x, y):
    time.sleep(3)
    print 'add result: %d' % (x + y,)

@function_performance_statistics(False)
def mul(x, y=1):
    print 'mul result: %d' % (x * y,)

add(1, 1)
mul(10)
#上述代码想要实现一个性能分析器,并接收一个参数,来控制性能分析器是否生效,其运行效果如下所示:
#add result: 2
#used time: 0
#mul result: 10
#上述代码中装饰器的调用等价于:
add = function_performance_statistics(True)(add(1, 1))
mul = function_performance_statistics(False)(mul(10))

设计模式中的装饰器

    饮料店的点餐系统
  • 饮料类

class Beverage(): name = "" price = 0.0 type = "BEVERAGE" def getPrice(self): return self.price def setPrice(self, price): self.price = price def getName(self): return self.nam

# 继承的方式和接口的区别是啥?
class coke(Beverage):
    def __init__(self):
        self.name = "coke"
        self.price = 4.0


class milk(Beverage):
    def __init__(self):
        self.name = "milk"
        self.price = 5.0

除了基本配置,快餐店卖可乐时,可以选择加冰,如果加冰的话,要在原价上加0.3元; 卖牛奶时,可以选择加糖,如果加糖的话,要原价上加0.5元。怎么解决这样的问题? 可以选择装饰器模式来解决这一类的问题。首先,定义装饰器类:

class drinkDecorator():
    def getName(self):
        pass
    def getPrice(self):
        pass

class iceDecorator(drinkDecorator):
    def __init__(self,beverage):
        self.beverage=beverage
    def getName(self):
        return self.beverage.getName()+" +ice"
    def getPrice(self):
        return self.beverage.getPrice()+0.3

class sugarDecorator(drinkDecorator):
    def __init__(self,beverage):
        self.beverage=beverage
    def getName(self):
        return self.beverage.getName()+" +sugar"
    def getPrice(self):
        return self.beverage.getPrice()+0.5

构建好装饰器后,在具体的业务场景中,就可以与饮料类进行关联。 以可乐+冰为例,示例业务场景如下:

if  __name__=="__main__":
    coke_cola=coke()
    print "Name:%s"%coke_cola.getName()
    print "Price:%s"%coke_cola.getPrice()
    ice_coke=iceDecorator(coke_cola)
    print "Name:%s" % ice_coke.getName()
    print "Price:%s" % ice_coke.getPrice()

打印结果如下:
Name:coke
Price:4.0
Name:coke +ice
Price:4.3

其他

https://yq.aliyun.com/articles/70737?utm_content=m_15328 https://segmentfault.com/a/1190000012064562

Java装饰器模式

C++装饰器模式