如何通过装饰者模式把你的猫变成女朋友

编程入门 行业动态 更新时间:2024-10-23 07:23:45

如何通过装饰者模式把你的猫变成<a href=https://www.elefans.com/category/jswz/34/1769403.html style=女朋友"/>

如何通过装饰者模式把你的猫变成女朋友

如何通过装饰者模式把你的猫变成女朋友

真不是标题党,看官仔仔细细看完例子,就知道如何把猫变成女朋友了(狗头保命)

定义

装饰者模式允许用户用组合的方式而不是继承对已有的类的功能进行扩展,扩展后的类为装饰者,被扩展的类为被装饰者,装饰者与被装饰者具有相同的方法签名,而且有自己另外的方法。

应用场景

当使用继承的方式无法很好地对代码进行扩充时,可以考虑用装饰者模式,比如有一个奶茶基类,开始只有奶和茶,想做出珍珠奶茶,我们用继承实现一个珍珠奶茶类,想做出芒果味奶茶,我们用继承实现一个芒果味奶茶类,此时如果我们要做芒果味珍珠奶茶,则无法复用前面两个类,只能再用继承实现一个芒果味珍珠奶茶类。品种多了的话奶茶类的子类会非常多,此时如果用装饰器模式的话,把奶茶的风味跟调料实现为装饰者类,那么很容易就可以得到奶茶与各种添加品的自由组合,芒果味珍珠奶茶、西瓜味珍珠奶茶、榴莲味珍珠布丁椰子冻奶茶等。

例子

再用一个更有趣的例子来解释装饰者模式,我们有狗和猫两个动物类,假设现在动物有两种变种,一种是外星动物,一种是可变形动物,我们先看用装饰者模式如何设计,下面是uml类图。

Animal是接口,只定义了一个方法makeNoise,AnimalDecorator与Animal具有一样的接口,实现AnimalDecorator接口的类还需要有一个变量存放Animal实例,这就是被装饰的animal,AlienDecorator除了能发出声音makeNoise外,还有统治地球的方法ruleTheEarth,TransformDecorator除了能发出声音makeNoise外,还有变成女朋友的方法transformToGirlFriend。当我们用AlienDecorator装饰Cat时,我们就得到了一只外星猫,用TransformDecorator装饰Cat时,就得到了一只变形猫。下面是代码
Animal.java

package priv.mxz.decorator_pattern;public interface Animal {void makeNoise();
}class Cat implements Animal{@Overridepublic void makeNoise() {System.out.println("meow meow");}
}class Dog implements Animal{@Overridepublic void makeNoise() {System.out.println("woof woof");}
}

AnimalDecorator.java

package priv.mxz.decorator_pattern;interface AnimalDecorator extends Animal {@Overridevoid makeNoise();
}class AlienDecorator implements AnimalDecorator{private Animal animal;public AlienDecorator(Animal animal){this.animal=animal;}@Overridepublic void makeNoise() {System.out.println("I am an alien  but I pretend to be an animal ");animal.makeNoise();}public void ruleTheEarth(){System.out.println("I don't pretend now! I am an alien!! I will rule the Earth!");}
}class TransformDecorator implements AnimalDecorator{private Animal animal;public TransformDecorator(Animal animal){this.animal=animal;}@Overridepublic void makeNoise() {System.out.println("I can transform to your girlfriend but I pretend to be an animal");animal.makeNoise();}public void transformToGirlFriend(){System.out.println("I am a transformer actually, now I transform to be your girl friend");}}

DecoratorPattern.java

package priv.mxz.decorator_pattern;public class DecoratorPattern {private Animal animal;public DecoratorPattern(Animal animal){this.animal=animal;}public static void main(String[] args) {System.out.println("Now you have a real cat");DecoratorPattern you=new DecoratorPattern(new Cat());you.animal.makeNoise();System.out.println("Now you have a alien cat");you.animal=new AlienDecorator(new Cat());you.animal.makeNoise();AlienDecorator alien_cat=(AlienDecorator)you.animal;System.out.println("Now your alien cat is going to rule the Earth");alien_cat.ruleTheEarth();System.out.println("Now you have a transform cat");you.animal=new TransformDecorator(new Cat());you.animal.makeNoise();System.out.println("Now your cat transform to be your girlfriend");TransformDecorator transform_cat=(TransformDecorator)you.animal;transform_cat.transformToGirlFriend();System.out.println("Now you have a alien dog");you.animal=new AlienDecorator(new Dog());you.animal.makeNoise();System.out.println("Now your alien dog is going to rule the Earth");AlienDecorator alien_dog=(AlienDecorator)you.animal;alien_dog.ruleTheEarth();}
}

运行结果如下

Now you have a real cat
meow meow
Now you have a alien cat
I am an alien  but I pretend to be an animal 
meow meow
Now your alien cat is going to rule the Earth
I don't pretend now! I am an alien!! I will rule the Earth!
Now you have a transform cat
I can transform to your girlfriend but I pretend to be an animal
meow meow
Now your cat transform to be your girlfriend
I am a transformer actually, now I transform to be your girl friend
Now you have a alien dog
I am an alien  but I pretend to be an animal 
woof woof
Now your alien dog is going to rule the Earth
I don't pretend now! I am an alien!! I will rule the Earth!Process finished with exit code 0

DecoratorPattern中有函数入口,我们先有了一只真猫,然后让它叫一下,然后又有了一只外星猫,它除了会叫还会统治地球,然后又有了一只变形猫,它除了会叫还能变成你的女朋友(看吧我不是标题党)。最后我们有了一只外星狗,它除了会汪汪汪还会统治地球。

如果不用装饰者模式,而是用纯继承的方式,那么我们需要实现外星狗,外星猫,变形狗和变形猫,此时接口和类的总数目为8,而装饰者模式只有7(见上面uml图),如果加上猪、外星猪、变形猪,用继承的方法需要添加3个类,而用装饰者模式只需要加一个猪的类,由此可见装饰者模式的优雅与高复用。

java IO中的装饰者模式

发一张《Head First设计模式》中关于javaIO的截图

可以看出这个类图跟上述外星猫狗的例子的uml类图是十分相似的,第二层前三个类是实际的IO类,对应从文件、字符串、字节数组中读取数据,第三层中的装饰者规定了读取数据的方式,如缓存读取,具体的使用例子类似这样
InputStream in=new BufferedInputStream(new FileInputStream(“test.txt”));

python中的装饰器

下面是python使用装饰器修饰函数的一个例子,最后是程序的输出,通过在函数定义前加上@decorator_name,就可以用decorator_name函数修饰函数,例子中的装饰器作用可以理解为
target=deco(target),最后输出可以看到target已经变成了inner函数而不是target。

def deco(func):def inner():print('running inner()')func()return inner@deco
def target():print('running target()')target()
print(target) # running inner()
# running target()
# <function deco.<locals>.inner at 0x0000019B473D5620>

跟java的装饰者模式相比,python的装饰器灵活度更弱,一旦在函数前加了修饰器,相当于这个函数被装饰器给替代了,无法再运行原函数,而java的装饰者模式是可以拿到被装饰者的实例的,可以自行选择是否添加装饰器。

装饰者模式的优缺点

优点

  1. 装饰者模式很好地体现了开放-关闭原则,装饰者通过与被装饰者继承相同的类或实现相同的接口来拥有与被装饰者一样的方法签名,对外表现出与被装饰者一样的方法签名,但又不改变被装饰者内部的实现,而是通过组合来扩展被装饰者的功能。
  2. 对于调用程序来说装饰者是透明的,它可以依然认为它是被装饰者,除非查看具体类型。但当一个物体像鸭子一样叫,像鸭子一样走路,像鸭子一样外形,我们就可以认为它就是鸭子(人生苦短,我用python)
  3. 提供了比继承更好的复用代码的方式,装饰者与被装饰者可以任意组合

缺点

  1. 如果调用程序中有依赖于被装饰者具体类型的代码,则不能使用装饰者模式,因为装饰者装饰被装饰者后返回的是类型是装饰者。
  2. 装饰者模式会导致需要小对象的出现,如果过度使用,会让程序变复杂

更多推荐

如何通过装饰者模式把你的猫变成女朋友

本文发布于:2024-02-11 15:29:45,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1681747.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:女朋友   模式

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!