经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
装饰者模式
来源:cnblogs  作者:纳兰小依  时间:2019/9/29 9:03:27  对本文有异议

      装饰者模式能够动态地将责任附加到对象上,在扩展对象功能方面比继承更加灵活,具体来说,装饰者模式将行为委托给相应的包装对象,并添加上自己的对应逻辑来实现特定的功能。装饰者模式的UML图如下:

      首先需要有被装饰的组件接口和具体组件,然后有装饰者对象,由于装饰者对象需要能够代替组件,所以要继承组件接口,并组合组件对象来完成委托任务。

      下面以一个简单的快餐店为例子来介绍装饰者模式的用法。快餐店会有炒面、炒饭这些快餐,可以额外附加鸡蛋、火腿、培根这些配菜,当然加配菜需要额外加钱,每个配菜的价钱通常不太一样。按照上面的UML类图,先定义组件接口(快餐)和具体组件(炒饭、炒面)。

  1. 1 //快餐接口
  2. 2 public interface FastFood {
  3. 3 float getCost(); //获取价格
  4. 4 String getDescription(); //获取描述
  5. 5 }
  6. 6
  7. 7 //炒饭
  8. 8 public class FriedRice implements FastFood{
  9. 9 private float price = 5;
  10. 10 String description = "炒饭";
  11. 11 @Override
  12. 12 public float getCost() {
  13. 13 return this.price;
  14. 14 }
  15. 15
  16. 16 @Override
  17. 17 public String getDescription() {
  18. 18 return this.description;
  19. 19 }
  20. 20 }
  21. 21
  22. 22 //炒面
  23. 23 public class FriedNoodles implements FastFood{
  24. 24 private float price = 5;
  25. 25 String description = "炒面";
  26. 26 @Override
  27. 27 public float getCost() {
  28. 28 return this.price;
  29. 29 }
  30. 30
  31. 31 @Override
  32. 32 public String getDescription() {
  33. 33 return this.description;
  34. 34 }
  35. 35 }

      接下来是配菜相关接口和类:

  1. 1 //配菜
  2. 2 public interface Garnish extends FastFood{
  3. 3 String getDescription();
  4. 4 }
  5. 5
  6. 6 //鸡蛋
  7. 7 public class Egg implements Garnish{
  8. 8 float price = 1.5f;
  9. 9 String description = "鸡蛋";
  10. 10 private FastFood fastFood;
  11. 11
  12. 12 public Egg(FastFood fastFood){
  13. 13 this.fastFood = fastFood;
  14. 14 }
  15. 15
  16. 16 @Override
  17. 17 public float getCost() {
  18. 18 return this.price + fastFood.getCost();
  19. 19 }
  20. 20
  21. 21 @Override
  22. 22 public String getDescription() {
  23. 23 return this.description + fastFood.getDescription();
  24. 24 }
  25. 25 }
  26. 26
  27. 27 //培根
  28. 28 public class Bacon implements Garnish{
  29. 29 private float price = 2f;
  30. 30 private String description = "培根";
  31. 31 private FastFood fastFood;
  32. 32
  33. 33 public Bacon(FastFood fastFood){
  34. 34 this.fastFood = fastFood;
  35. 35 }
  36. 36
  37. 37 @Override
  38. 38 public float getCost() {
  39. 39 return this.price + fastFood.getCost();
  40. 40 }
  41. 41
  42. 42 @Override
  43. 43 public String getDescription() {
  44. 44 return this.description + fastFood.getDescription();
  45. 45 }
  46. 46 }
  47. 47
  48. 48 //火腿
  49. 49 public class Ham implements Garnish{
  50. 50 float price = 1f;
  51. 51 String description = "火腿";
  52. 52 private FastFood fastFood;
  53. 53
  54. 54 public Ham(FastFood fastFood){
  55. 55 this.fastFood = fastFood;
  56. 56 }
  57. 57
  58. 58 @Override
  59. 59 public float getCost() {
  60. 60 return this.price + fastFood.getCost();
  61. 61 }
  62. 62
  63. 63 @Override
  64. 64 public String getDescription() {
  65. 65 return this.description + fastFood.getDescription();
  66. 66 }
  67. 67 }

      接下来就可以点几份快餐测试一下代码了:

  1. 1 public class DecoratorPatternTest {
  2. 2 public static void main(String[] args){
  3. 3 FastFood friedRice = new FriedRice();
  4. 4 System.out.println(friedRice.getDescription() + " " + friedRice.getCost() + "元");
  5. 5 FastFood friedNoodles = new FriedNoodles();
  6. 6 friedNoodles = new Egg(friedNoodles);
  7. 7 friedNoodles = new Ham(friedNoodles);
  8. 8 System.out.println(friedNoodles.getDescription() + " " + friedNoodles.getCost() + "元");
  9. 9 friedRice = new Bacon(friedRice);
  10. 10 System.out.println(friedRice.getDescription() + " " + friedRice.getCost() + "元");
  11. 11 }
  12. 12 }

      输出如下:

  1. 炒饭 5.0
  2. 火腿鸡蛋炒面 7.5
  3. 培根炒饭 7.0

      现在来回顾一下上面的类结构,我们在点培根炒饭时,先创建一个炒饭对象,然后用培根对象把炒饭包装了一下,当计算价格以及输出描述时,我们的做法是获取装饰者(培根)对象的价格和描述,同时需要获取组件(炒饭)的价格我描述,我们将这项任务委托给组件来完成,火腿鸡蛋炒面也是同样的道理。装饰者继承组件,使得装饰者可以包装任意的具体组件,同样也可以包装装饰者;同时,装饰者也可以加入自己的逻辑,给组件增添不一样的行为,例如这里在技术价格以及获取描述时,除了返回装饰者自己的属性,还增加了返回组件属性的逻辑。

      其实装饰者模式在Java API中使用的很多,举个很简单的例子,当我们需要读取文件时,很可能会写出下面的代码:

  1. 1 BufferedReader bf = new BufferedReader(new FileReader(new File("./test.txt")));

      其中BufferedReader和FileReader就充当了装饰者的作用,而File则是被装饰的组件,还有一些其他的API也用到了装饰者模式,需要大家自己去摸索了。

      参考文献:

      <<Head First设计模式>>

原文链接:http://www.cnblogs.com/NaLanZiYi-LinEr/p/11605616.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号