jungleford's profileJungleford's Home MSN 总舵PhotosBlogListsMore ![]() | Help |
|
12/1/2007 SmartCalendar relaunched最近家里有点闹心的事,没来更新。 SC 0.1β在sourceforge上停了一年多了(参见2006年3月14日和3月22日两贴),现在重新拾起来完全是因为做那个被cancel项目激励的,从这个项目上得到了pattern上的更进一步的认识,于是思考这些经验是否可以用来重构SC。要感谢水木Java版那些对开源保持热情的年轻的人们,zms、kabbesy、dev、cjmm……,因为他们牵头创建了这个水木自己的开源项目站点:SMTHJava。 目前差不多做成型的是一些基本widget,完全GUI-independent,以及它们的Swing和SWT实现,这些基础widget是用来拼时钟/日历这些高级widget的积木块。想法就是类似IoC那样运行时注册,发现,并启用具体采用哪一套GUI Adapter实现方案(Swing or SWT)。简单介绍几个基本概念: ● Iterator(遍历器) 这是在0.1β里就用到的概念。我们观察一个acceptable的日历组件应该有这么一个特征:可按输入(按钮或输入)转到指定月/年上,尤其是相邻的前/后一个月/年。这个行为往往可以适用到很多组件上,譬如通常用到的table“翻页”行为,譬如VB流行的年代常用的DAO/ADO组件。所以我这里抽象出一种行为叫Iterator,“可遍历”,当然它是一个interface,它包含这么几个最常用的方法: moveXXX():如moveFirst/moveLast/movePrevious/moveNext,即这个数据结构是“可游动”的,而且是“可线形游动”的(movePrevious/moveNext,而moveFirst/moveLast是两个特殊的游动方式)。 getXXX():如getFirst/getLast/getPrevious/getNext,我们知道设计栈(Stack)这种数据结构的时候为方便起见会加上一个peek()方法,意思是让你得到栈顶元素而不将其弹出栈(瞟一眼但不去动它),这里也是类似的意思,得到某个位置上的元素而不移动游标。 getCurrentItem()/setCurrentItem():顾名思义,得到当前游标上的元素或移动游标到某个元素。这是一种非线性遍历方式。 isRollback()/setRollback():这个名字不知道是不是起得合适,我的本意是这个遍历器是不是“可循环”的,即到达头或尾再往下遍历是不是可以跳到尾或头开始,如果是循环队列的话需要做模运算确定index。 我们看到“遍历器”实际上是一个增强型的队列(循环或非循环),在java.util包中你也能找到Iterator这个接口,但它是单向线性遍历的,只有next()方法。在这个接口上我写了几个基础遍历器,用于封装对整数的遍历,对List(线性列表)的遍历,对日历的遍历,这几个是GUI无关的组件;在GUI中有继承扩展了几种,如对文本框(尤其是格式化文本框)的遍历,对combo box的遍历。 ● IterableWidget(可遍历组件) Iterator是个什么东东呢?简单的说它就是一个helper,可以用来告诉UI应该怎么做,如果要扯到MVC的话,Iterator就是一个controller,UI是view,Iterator要遍历的东西(比如comobox的item list)就是model了。我定义IterableWidget是这么一个玩意,它将一种UI和一个Iterator绑定在一块,这就成了一种稍微高级一点的GUI组件。我们能够想到的有哪些“可遍历组件”呢?上面说了,显示整数的文本框,combo box,spinner,我要做的calendar界面,可翻页的table,DAO/ADO组件等等。 ● IterateAction IterableWidget仅仅是“可遍历”,要激发它动作需要通过另一个组件(譬如按钮),我定义了一个IterateActionButton的组件用于把一个按钮和它要激发的遍历操作的若干个IterableWidget绑定在一起,这个按钮去激发IterableWidget的helper(即Iterator)进行遍历操作。 ● Adapter 这里需要对泛型、Adapter模式和IoC稍微有点了解了。我的目的是想达到GUI-independent,对比Swing和SWT,你会发现它们差得十万八千里,除了Object这个爪哇人都知道的根对象,两者竟然没有交集,那你怎么来搞GUI无关性?怎么抽取共同行为?于是乎,泛型就来了吧?把一个具体的GUI对象适配成我这套GUI library当中的对象,具体要用的时候(比如布局,这个GUI-independent做不了)再getAdaptee()还原成具体的GUI对象(Swing或SWT或其它什么玩意)。不管怎么样,地球人总有一套必不可少的公共组件:按钮、标签、文本框、容器、对话框、窗口……,再高级一点就表格、树……,更高级一点就像我们要做的这个日历等等。widget越基础,行为就越容易抽象。 ● 一点puzzle 写的时候往往是反复重构,解耦程度越高,重构的代价就越低,这也符合agile的办事风格。我比较为难的是权衡保留泛型参数的规模上,如果你内部属性的类型要做到“精确”,势必要有较多的泛型参数来约束,这个好处是减少类型检查的hard code,但泛型参数的增加会随着类库的继承和复用层次的增长而增长,这是很讨厌的一件事,因为你会发现为了创建一个对象需要指定N多个你并不关心的这个对象内部属性的具体类型。所以,我妥协了,人是容易妥协的动物,我对一个widget通常只用一个泛型参数(如果它需要用泛型的话),这个参数就是指代它需要适配的那个GUI组件的类型;所有接口,目前只有IAdapter使用了泛型,因为我们需要得到adaptee,其它接口只定义行为;widget内部如果用到composite的widget的话,都用这个widget的接口类型。 以上大概通过代码更好理解一些,代码我放单位的机器上了,过两天传上来。
重新启动的SmartCalendar项目主页在这里,主页快照:
TrackbacksThe trackback URL for this entry is: http://jungleford.spaces.live.com/blog/cns!E733CCEEE4BE0FB2!2015.trak Weblogs that reference this entry
|
|
|