数据设计程序-装饰者模式

问题: 我们生活在海量的数据库中,如何高效梳理和归纳我们接触到的数据?

解决办法: 通过数据设计一个可靠的设计, 既有输入、又有过程的函数、最后获得响应目的的数据

案例: 装饰者模式的运用

1. 思路及想法

  • 执行某个函数f,插入某段代码g,不影响函数f,但是显示出代码g的结果 函数f指的就是foo和bar等(在我们数据设计程序世界里面,函数是最小单元)
def foo():
    print('foo.....')
    time.sleep(2)
    print(f"end-start: {end-start}")
foo()

def bar():
    print('bar .....')
    time.sleep(1)
    print(f"end-start: {end-start}")
bar()

我们希望添加的插入代码块g如下,即增加计时器或者其他logger切面功能

start=time.time()
print('foo.....')
time.sleep(2)
end=time.time()
print(f"end-start: {end-start}")

start=time.time()
print('bar .....')
time.sleep(1)
end=time.time()
print(f"end-start: {end-start}")

2. 初始解决方案

我们出发点认为所有函数是first class对象,这样就可以把函数当做变量来对象。

有了这个出发点,咱们就可以设计我们的解决方案

  • 新建一个showTime函数,函数f作为变量
  • 调用showTime函数,把函数f传入作为输入变量,得到我们想要的结果.
## <2022-01-16 22:13>测试通过
def showTime(f):
    start=time.time()
    f()
    end=time.time()
    print(f"end-start: {end-start}")

def fooUpdate():
    print('fooUpdate.....')
    time.sleep(2)

def barUpdate():
    print('barupdate.....')
    time.sleep(1)
showTime(fooUpdate)
showTime(barUpdate)

存在问题:你改变了之前很多业务员的代码习惯,必须调用showTime了(不满足我们初始的思路)

3. 解决showTime的缺点

## <2022-01-16 22:12> 测试通过
def foo():
    print("fooo ......")
    time.sleep(1)
def showTime(f):
    def inner():
        start= time.time()
        f()
        end= time.time()
        print(f"end-start: {end-start}")
    return inner

foo =showTime(foo)
foo()

上面基本解决了我们的想法,但是写法不太友好,python引入了注解写法,更为简洁,如下所示: 即_注解等效于调用了一次外部程序。

## <2022-01-16 22:12> 测试通过
def showTime(f):
    def inner():
        start= time.time()
        f()
        end= time.time()
        print(f"end-start: {end-start}")
    return inner

@showTime  ## 等价于foo=showTime(foo)
def foo():
    print("fooo ......")
    time.sleep(1)

# foo =showTime(foo) ## 等价于@showTime
foo()

但是上面解决的仅仅是无参函数,如果我们的函数f有很多参数? 即add1

def add1(*a, **b):
    sums=0
    for i in a:
        sums=sums+i
    print(sums)
    time.sleep(1)
    print(f"a= {a} , b={b}")
add1(1,2,3,4,hf=3,hfd=4)

4. 多参数解决方案改进

  • 通过引入一个wrapper函数,考虑args和kwargs来解决多常数问题
def showtime(func):
    def wrapper(*args,**kwargs):
        start=time.time()
        func(*args,**kwargs)
        end=time.time()
        print(f"end-start  is  {end-start}")
        if flag==2:
            print("已将上述操作操作录入文件")
    return wrapper
return showtime
## <2022-01-16 22:12> 测试通过
## 多参数解决方法
def showtime1(func):
    def wrapper(*args,**kwargs):
        start=time.time()
        func(*args,**kwargs)
        end=time.time()
        print(f"end-start  is  {end-start}")
    return wrapper

@showtime1
def add(*a,**b):
    time.sleep(1)
    sum=0
    for i in a:
        sum+=i
    print(f"sum of {a} is equal to {sum}")

add(1,2,3,5,6)

上面还有个缺陷,如果我的showtime1有参数? 即比如@showtime1(authtype=‘local’) 我的日志可能是网络记录、本地记录或者其他方式,该如何解决?

5. 日志参数解决方法

  • 思路: 再增加一层函数,考虑参数authtype,并返回showtime函数

    ## <2022-01-16 22:15> 测试通过
    import time
    def logger(flag=1):
        def showtime(func):
            def wrapper(*args,**kwargs):
                start=time.time()
                func(*args,**kwargs)
                end=time.time()
                print(f"end-start  is  {end-start}")
                if flag==2:
                    print("已将上述操作操作录入文件")
            return wrapper
        return showtime
    
    @logger(flag=2)
    def add(*a,**b):
        time.sleep(1)
        sum=0
        for i in a:
            sum+=i
        print(f"sum of {a} is equal to {sum}")
    
    add(1,2,3,4)

至此,我们完成了一种完美的添加时间的日志记录功能,支持初始函数的多参数功能,支持日志记录的参数类型指定,三层函数嵌套实现装饰者模式。

6. 案例1 网站登录功能(无多参数功能)

user="yzl"
passwd='123'

loginStatus=False
def login1(authtype):
    if loginStatus == False:
        def wrapper(f):
            print(f"authtype is {authtype}")
            if authtype=="jingdong":
                username = input("input your Username:")
                password = input("input your Password:")
                if( username == user and password == passwd):
                    print("welcome to Jd")
                    login_Status=True
            elif authtype=="weixin":
                username = input("input your Username:")
                password = input("input your Password:")
                if( username == user and password == passwd):
                    print("welcome to Jd")
                    login_Status=True
            else:
                print("无效")
        return wrapper
    else:
        pass

@login1(authtype="jingdong")
def home():
    print("欢迎来到主界面")

@login1(authtype="weixin")
def finance():
    print("欢迎来到经融界面")  ## 登录完了 就应该具备记录登录状态功能,不需要重复输入,也就是单点登录功能

@login1(authtype="weixin")
def manager():
    print("欢迎来到管理界面")  ## 登录完了 就应该具备记录登录状态功能,不需要重复输入,也就是单点登录功能
Related
叶昭良
叶昭良
Engineer of offshore wind turbine technique research

My research interests include distributed energy, wind turbine power generation technique , Computational fluid dynamic and programmable matter.