工具软件   办公软件   操作系统   网络安全   设计在线   程序开发   教程宝典   软件下载   软件论坛
您的位置:软件 > 开发者网络 > 开发工具 > Java > 正文
Decorator模式中遭遇继承与聚合的冲突
[文章信息]
作者:M_D_R
时间:2005-03-07
出处:blog
责任编辑:方舟
[文章导读]
我们通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类
advertisement
专题教程宝典
【软件应用】
【办公软件】
【图形图像】
【网页制作】
【操作系统】
【网络安全】
【程序开发】
【日报周刊】
【多媒体教程】
· 天极软件应用多媒体教程
· 软件盗版与反盗版之战
· Windows开机关机故障分析及排除
· 图解PS按比例自动批量裁剪照片
· Visual FoxPro9.0构建管理系统图解
· 体验面对面的网络视频通讯
· 对付网页恶意代码
· Word动画教程:表格操作全接触
· JBuilder 2005开发Applet游戏全接触
· WinRAR操作技巧与另类应用
[正文]
  一:背景:Decorator

  *Decorator 常被翻译成"装饰",我觉得翻译成"油漆工"更形象点,油漆工(decorator)是用来刷油漆的,那么被刷油漆的对象我们称decoratee.这两种实体在Decorator 模式中是必须的。

  *Decorator 定义:

  动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator 模式相比用生成子类方式达到功能的扩充显得更为灵活。

  *为什么使用Decorator?

  我们通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的。

  使用Decorator 的理由是:这些功能需要由用户动态决定加入的方式和时机.Decorator 提供了"即插即用"的方法,在运行期间决定何时增加何种功能。

  *对于该模式,初步归纳为

  1.基本功能为接口

  2.Decorator参数为接口本身也为接口以便为下一个Decorator的参数

  3.基本功能类实现接口 并作为Decorator构造函数的参数,以便在此基础上添加新功能

  4.额外功能由Decorator中的数据结构处理
 
  二:问题

  这是一段Decorator设计模式的实现例子如下:

  基本功能:Counter类
  需要添加的功能

  1:上限控制

  2:下限控制

import java.io.*;
class Counter{
 private int value;
 public Counter(int v){
  System.out.println("init me here in The Counter with value!");
  value=v;
 }

 public Counter(Counter cc){
  System.out.println("init me here in The Counter with class!");
  value=cc.value;
 }

 public int read_value(){
  System.out.println("read me here The value is:"+value);
  System.out.println("read me here in The Counter!");

  return value;
 }

 public void increment(){
  System.out.println("increment me here in The Counter !");
  value++;
 }

 public void decrement(){
  System.out.println("decrement me here in The Counter !");
  value--;
 }
}

class Decorator extends Counter
{
 Counter counter;
 public Decorator(Counter c)
 {
  super(c);
  System.out.println("init me here with class Decorator!");
 } 
}

class UpperLimit extends Decorator//上限控制
{
 public UpperLimit(Counter c)
 {
  super(c);
  counter=c;
  System.out.println("init me here with class UpperLimit!");
 }
 public void increment()
 {
  if(counter.read_value()>20)
  {
   System.out.println("Too High");
  }
  else
  {
   System.out.println("increment me here with class UpperLimit!");
   counter.increment();
  }
 }
 /*public void decrement()
 {
  counter.decrement();
 }
 public int read_value()
 {
  return counter.read_value();
 }*/

}

class LowerLimit extends Decorator//下限控制
{
 public LowerLimit(Counter c)
 {
  super(c);
  counter=c;
  System.out.println("init me here in The Counter with class LowerLimit!");
 }
 public void decrement()
 {
  System.out.println("Class value :"+read_value());
  System.out.println("Dec value :"+counter.read_value());
  if(counter.read_value()<=0)
  {
   System.out.println(counter.read_value());
   System.out.println("Too Low");
  }
  else
  {
   System.out.println("decrement me here in The Counter with class LowerLimit!");
   counter.decrement();
  }
 }
 /*public void increment()
 {
  counter.increment();
 }
 public int read_value()
 {
  return counter.read_value();
 }*/
}

class CounterFactory
{
 public static Counter createCounter(int value,int op)
 {
  switch(op)
  {
   case 1:
   {
    return new Counter(value);
   }
   case 2:
   {
    return new UpperLimit(new Counter(value));
   }
   case 3:
   {
    return new LowerLimit(new Counter(value));
   }
   default:
   {
    return new UpperLimit(new LowerLimit(new Counter(value)));
   }
  }
 }

}
class Console
{
 private static BufferedReader read=new BufferedReader(new InputStreamReader(System.in));

 public static int readInt(String index){
  System.out.println(index);
  try{
   return Integer.parseInt(read.readLine());
  }
  catch(Exception e){
   return 0;
  }
 }
}

public class Q1s{
 public static void main(String[] args){
  System.out.println("Counter Type:");
  System.out.println("1: Normal");
  System.out.println("2: Upper Limit");
  System.out.println("3: Lower Limit");
  System.out.println("4: Upper & Lower Limit");
  int option=Console.readInt("Enter Choice:");
  Counter c = CounterFactory.createCounter(6,option);
  int choice=1;
  while(choice!=4){
   System.out.println("1: Increment");
   System.out.println("2: Decrement");
   System.out.println("3: Read Value");
   System.out.println("4: Exit");
   choice=Console.readInt("Enter Choice:");
   switch(choice){
    case 1: c.increment(); break;
    case 2: c.decrement(); break;
    case 3: int v=c.read_value();
    System.out.println("Value="+v);break;
   }
  }
 }
}

  按如下步骤运行出现明显问题:

  1:选3,"Lower Limit",

  2:选3,"Read Value" 获得的值是 6
 
  3:选1,"Increment"(此后value值应为 7)

  4:选3,"Read Value" 获得的值是 7(正确)

  5:选2,"Decrement"(此后的value值应为 6)

  6:选3,"Read Value" 获得的值为 7 (问题出现了)

  考察 Upper Limit 时同样出现该问题

  三:追究

  从输出的追踪语句可以看出在class LowerLimit的decrement方法的开始两输出语句具有明显的指导意义而其中一方法是调用的来自父类的read_value()而另一个为聚合对象的read_value()。在上面步骤的第六步两句分别输出

Class value :7
Dec value :6

  可见,有两份value的存在。问题是两份如何产生?

  继续观察,工厂在开关语句选中case 3时调用的是

return new LowerLimit(new Counter(value));

  其中新建一匿名对象为参数,继续追踪该过程,发现在class Decorator 中该匿名对象被Decorator的属性指向,而在指向之前,Decorator还把该匿名对象传给其父类,而父类取得该对象后仅仅是取出该对象中value的拷贝,由此有两份value存在:

  1.在Decorator自身中(父类的value)

  2.也在Decorator自身中(成员变量Counter的value属性)!

  问题渐渐明朗,再次观察class LowerLimit,它仅仅实现了decrement()方法,也就是说,对LowerLimit调用read_value()与increment()时,其全部追溯到其父类中执行,而被作用的值value为第一类型值。对LowerLimit调用decrement()方法时,该方法是用其成员变量Counter的read_value()来执行的。此时被作用的值为第二类型值.所以会出现value值不同步的现象。

  四:解决

  很明显,解决方法在于仅使用其中一份value值,当然,Decorator本身的目的便在于避免使用继承,所以应当覆盖原有的方法,用成员变量的方法实现内部实现。也就是将代码中的注释去掉.

  五:小结

  父类获得了只是值的拷贝 而本身的聚合对象获得了(参数的)全部的引用否则 如果有方法没有覆盖原来的 则该方法将沿用父类的 在拷贝的值(value)上操作而被覆盖了的方法的将对本身聚合的对象中的值(value)进行操作 于是两value值产生分歧。

  从Decorator模式本身的用意可知:在已有的类基础上的动态功能的添加(不是用继承来实现,以防太深,难以控制)所以,构造函数的参数应当也必须作为"已有的类基础"来对待,也就是说,自身的聚合对象必须是
该参数的引用,所有的方法也必须重造,否则将落入继承的陷阱。

发表评论推荐给朋友我想参加相关培训打印我对此感兴趣订阅电子杂志
相关内容焦点新闻
  • Eclipse 走上榜首 照亮Java众生
  • Taglib原理和实现:再论El和JSTL标签
  • Java桌面应用程序设计新贵:SWT 简介
  • CORBA技术探索起步
  • 用JBuilder9制作EXE文件不公开秘笈
  • 专家:手机将实现一键通 能当对讲机使用
  • 中国发力切食网游蛋糕 政府出台扶持政策
  • 英国音像工业协会:非法下载音乐要被重罚
  • 电信运营商各自拿方案 过期卡余额有望退还
  • 网络立法:网络虚拟财产何时能得到法律关怀
  • 网络立法:用法律为青少年打造健康网络空间
  • 网络立法:“网络牛皮癣”真的无法根治吗?
  • 谨防新型木马病毒“美女”盗窃QQ账号密码
  • Advertisement

    天极无线


    奇妙科幻|美好风光|清风车影|漫画卡通|星座生肖|明星写真|动物世界
    老鼠爱大米
    挥着翅膀的女孩
    女人味
    栀子花开
    白月光
    刚刚好
    江南
    快乐崇拜
    亲爱的你怎么不在我身边
    小薇
    2002年的第一场雪
    有多少爱可以重来
    我的地盘
    七里香
    情人
     
    老鼠爱大米 老板电话
    冲动的惩罚 七里香
    我不是黄蓉 女生撒娇
    盛夏的果实 坚持到底
    孤单北半球 眉飞色舞
    挪威的森林 可爱女人
    最浪漫的事 老板电话

    CSEEK搜索