装饰器模式

简介

看到装饰会想到啥,蛋糕上的裱花?礼物盒上的蝴蝶结?还是礼帽上的羽毛?

这些小东西并不是必要的,蛋糕可以没有裱花,礼物盒可以没有蝴蝶结,礼帽可以没有羽毛。

但是添加了这些小东西,却可以让同一个物品展现出不同的模样。不同的裱花可以做出不同样式的蛋糕,不同的蝴蝶结也可以让礼物盒展现出不同的样式,不同的羽毛可以让礼帽表达不同的意思。

装饰器模式的设计理念就是为已经存在的对象添加装饰


正文

装饰器模式

看过简介的描述,我们可以知道,装饰器模式和类的继承是不一样的,因为装饰器具有以下几点特点:

  1. 在不改变原有对象的条件下,为对象添加新的“样式
  2. 即插即用

 下面我们先用一个小例子,演示一下

class Coke:
    name = "coke"
    price = 3

    def get_name(self):
        print(self.name)

    def get_price(self):
        print(self.price,"元")


class Ice:

    name  = "ice"
    price = "0.3"

    def __init__(self,drink):
        self.drink = drink
    
    def get_name(self):
        self.drink.get_name()
        print("加",self.name)

    def get_price(self):
        self.drink.get_price()
        print("加",self.price,"元")


c = Coke()
c.get_name()
c.get_price()
i = Ice(c)
i.get_name()
i.get_price()


从上面的例子我们可以看出,不加冰并不影响可乐本身的价格,加冰之后可乐发生了改变。

Python装饰器 

说到装饰器,我们不得不聊一下Python装饰器

Python的装饰器采用的就是我们的装饰器设计模式,那么,我们首先先来看一下Python的装饰器是怎么实现的。

函数装饰器

# 写法一
def ice(func):
    def wapper(*args):
        print("加冰")
        return func(*args)
    return wapper


class Coke:
    name = "coke"
    price = 3
    @ice
    def get_name(self):
        print(self.name)

    def get_price(self):
        print(self.price,"元")



c = Coke()
c.get_name()
c.get_price()
# 写法二
def ice(func):
    def wapper(*args):
        print("加冰")
        return func(*args)
    return wapper()


class Coke:
    name = "coke"
    price = 3

    def get_name(self):
        print(self.name)

    def get_price(self):
        print(self.price,"元")



c = Coke()
ice(c.get_name)
c.get_price()

类装饰器

class Ice():
    def __init__(self) -> None:
        self.name = "ice"

    def __call__(self,func):
        print(func)
        def wapper(*args):
            print("加",self.name)
            return func(*args)
        return wapper


class Coke:
    name = "coke"
    price = 3
    @Ice()
    def get_name(self):
        print(self.name)

    def get_price(self):
        print(self.price,"元")



c = Coke()
c.get_name()
c.get_price()

知识点一:@写法的作用

两种装饰器的写法都体现了一样的功能,和我们之前的装饰器模式不一样的地方是,装饰器模式需要将对象传入装饰器类中,和Python的函数装饰器写法二类似。

而Python的装饰器在调用的时候看起来好像是不需要将对象传入的。但是实际上我们在编写Python装饰器的时候,都会发现虽然在调用的时候没有传入对象,但是我们依旧会接受一个func的参数,并且输出在我们输出func*args的时候会发现,其实func就是被装饰的对象,*args这个元祖只有一个元素,就是Coke的实例

这就是@写法的作用,将@后面的对象添加()(type方法,涉及到元类)并且将@下面表示的方法作为参数传入被type()创建的对象中。

知识点二:__call__()方法的作用

将实例转化为可调用的对象,例子如下:

class CallTest:
    def __init__(self) -> None:
        pass

    def __call__(self, func):
        func()


def testdef():
    print("这是一个测试")

ct = CallTest()
ct(testdef)

让实例也可以像类一样被调用,Python中装饰器的类对象写法,就是通过__call__ 方法,将实例变成可以调用的对象,然后将被标记的函数当做参数传入。

知识点三:闭包 

当函数接收到传入的参数时,会在函数内部在定义一个函数(套娃),并且在内部定义的函数调用传进来的函数(给传入的func对象添加(),从访问函数地址,变成调用函数)。这种写法叫做闭包。

闭包的好处有可以隔离作用域,每个闭包都有属于自己的作用域。


总结

装饰器本质就是在不影响礼物本质的前提上,为礼物添加装饰,使得原有的礼物添加了新的样式。

在很多情况下都可以得到应用,比如说log记录,登录认证,添加钩子函数等等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值