??xml version="1.0" encoding="utf-8" standalone="yes"?>绯色av一区,国产精品国产三级国产aⅴ入口,国产精品第一第二http://www.aygfsteel.com/polygoncell/Finding... Thinking... Solving...zh-cnSun, 04 May 2025 00:41:11 GMTSun, 04 May 2025 00:41:11 GMT60使用重构U除丑陋的if else代码Q?Q?/title><link>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219786.html</link><dc:creator>polygoncell</dc:creator><author>polygoncell</author><pubDate>Sun, 03 Aug 2008 19:48:00 GMT</pubDate><guid>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219786.html</guid><wfw:comment>http://www.aygfsteel.com/polygoncell/comments/219786.html</wfw:comment><comments>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219786.html#Feedback</comments><slash:comments>37</slash:comments><wfw:commentRss>http://www.aygfsteel.com/polygoncell/comments/commentRss/219786.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/polygoncell/services/trackbacks/219786.html</trackback:ping><description><![CDATA[本文紧接<a id="Editor_Results_rprSelectionList_ctl01_LinkTitle" class="titlelink" href="../archive/2008/08/04/219785.html">使用重构U除丑陋的if else代码Q?Q?/a><br /> <br /> <span id="nb7o3" lang="EN-GB">上篇文章谈到如何能够d把这个switch也移除掉呢?很简单,我们只需要在getSystemStatePerformer()Ҏ被调用之前先创徏所? performer匿名cȝ实例Q然后在该方法被调用时直接返回对应的实力?如何具体实现呢? 用MapQ?L代码Q?br /> <br /> </span> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;">package</span><span style="color: #000000;"> de.jingge.refactoring;<br /> <br />  <br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> de.jingge.refactoring.SystemState.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.awt.Image;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.awt.image.BufferedImage;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.lang.reflect.Method;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.util.Collections;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.util.HashMap;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.util.Map;<br /> <br />  <br /> <br /> </span><span style="color: #008000;">/**</span><span style="color: #008000;"><br /> <br />  *<br /> <br />  * </span><span style="color: #808080;">@author</span><span style="color: #008000;"> gejing@gmail.com<br /> <br />  </span><span style="color: #008000;">*/</span><span style="color: #000000;"><br /> <br /> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> SystemStatePerformerFactory {<br /> <br />  <br /> <br /> </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> SystemStatePerformerFactory INSTANCE </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SystemStatePerformerFactory();<br /> <br />    <br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> Map</span><span style="color: #000000;"><</span><span style="color: #000000;">SystemState, SystemStatePerformer</span><span style="color: #000000;">></span><span style="color: #000000;"> performers;<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> SystemStatePerformerFactory() {<br /> <br /> }<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> SystemStatePerformerFactory getInstance() {<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> INSTANCE;<br /> <br />     }<br /> <br />    <br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;"> Map</span><span style="color: #000000;"><</span><span style="color: #000000;">SystemState, SystemStatePerformer</span><span style="color: #000000;">></span><span style="color: #000000;"> getPerformers()<br /> <br />             </span><span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {<br /> <br />         </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (performers </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">) {<br /> <br />             performers </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> HashMap</span><span style="color: #000000;"><</span><span style="color: #000000;">SystemState, SystemStatePerformer</span><span style="color: #000000;">></span><span style="color: #000000;">();<br /> <br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> call all @FactoryMethod using reflection</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />             </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> (Method m : getClass().getDeclaredMethods()) {<br /> <br />                 </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (m.getAnnotation(FactoryMethod.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">) </span><span style="color: #000000;">!=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">) {<br /> <br />                     SystemStatePerformer p </span><span style="color: #000000;">=</span><span style="color: #000000;"> (SystemStatePerformer) m.invoke(<br /> <br />                             </span><span style="color: #0000ff;">this</span><span style="color: #000000;">, </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> Object[]{});<br /> <br />                     performers.put(p.getState(), p);<br /> <br />                 }<br /> <br />             }<br /> <br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> make it readonly</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />             performers </span><span style="color: #000000;">=</span><span style="color: #000000;"> Collections.unmodifiableMap(performers);<br /> <br />         }<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> performers;<br /> <br />     }<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> SystemStatePerformer getSystemStatePerformer(SystemState state) </span><span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception{<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> getPerformers().get(state);<br /> <br />     }<br /> <br />  <br /> <br /> @FactoryMethod<br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> SystemStatePerformer createLoggedInPerformer() {<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SystemStatePerformer(LOGGEDIN, getImage(</span><span style="color: #000000;">"</span><span style="color: #000000;">loggedin.gif</span><span style="color: #000000;">"</span><span style="color: #000000;">)) {<br /> <br />  <br /> <br />             @Override<br /> <br />             </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> perform() {<br /> <br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;"> do something after logging in is successful,<br /> <br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;"> for example: show welcome dialog, open the last edit document, etc.</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />             }<br /> <br />         };<br /> <br />     }<br /> <br />  <br /> <br /> @FactoryMethod<br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> SystemStatePerformer createLoggedOutPerformer() {<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SystemStatePerformer(LOGGEDOUT, getImage(</span><span style="color: #000000;">"</span><span style="color: #000000;">loggedout.gif</span><span style="color: #000000;">"</span><span style="color: #000000;">)) {<br /> <br />  <br /> <br />             @Override<br /> <br />             </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> perform() {<br /> <br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;"> do something after logging out is successful,<br /> <br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;"> for example: free used resource, dispose GUI components, etc.            }</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />             }<br /> <br />         };<br /> <br />     }<br /> <br />  <br /> <br /> @FactoryMethod<br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> SystemStatePerformer createIdlePerformer() {<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SystemStatePerformer(IDLE, getImage(</span><span style="color: #000000;">"</span><span style="color: #000000;">idle.gif</span><span style="color: #000000;">"</span><span style="color: #000000;">)) {<br /> <br />  <br /> <br />             @Override<br /> <br />             </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> perform() {<br /> <br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;"> do something after the user is idle,<br /> <br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;"> for example: save the application state temporarily, lock the application, etc.</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />             }<br /> <br />         };<br /> <br />     }<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> Image getImage(String string) {<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> BufferedImage(</span><span style="color: #000000;">10</span><span style="color: #000000;">, </span><span style="color: #000000;">10</span><span style="color: #000000;">, BufferedImage.TYPE_4BYTE_ABGR);<br /> <br />     }<br /> <br /> }</span></div> <br /> <span id="u-921" lang="EN-GB">从代码中可以看出Q当getPerformersQ)Ҏ被第一ơ调用时Q我们会为每一个performer匿名cdZ个实例,q且它们纳入Map的管 理之中,以后每次调用的时候,直接从Map里面提取对应某个状态的performer可以了Q?switch可以舍弃了? @FactoryMethodq个注释是我自己写的Q用它主要是ؓ了避免每ơ新增加一个create***PerformerQ)Ҏ后,都必M? getSystemStatePerformerQ)?br /> <script type="text/javascript"><!-- google_ad_client = "pub-7331426433126513"; /* 728x90, created 7/11/08 */ google_ad_slot = "1570738323"; google_ad_width = 728; google_ad_height = 90; //--> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> <br /> </span>@FactoryMethod的代码如下:<br /> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;">package</span><span style="color: #000000;"> de.jingge.refactoring;<br /> <br />  <br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.lang.annotation.ElementType;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.lang.annotation.Retention;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.lang.annotation.RetentionPolicy;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.lang.annotation.Target;<br /> <br />  </span><span style="color: #000000;"><br /> <br /> @Retention(RetentionPolicy.RUNTIME)<br /> <br /> @Target({ElementType.METHOD})<br /> <br /> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> @</span><span style="color: #0000ff;">interface</span><span style="color: #000000;"> FactoryMethod {<br /> <br /> <br /> }</span></div> <br /> <span id="y.bf2078" lang="EN-GB">到这里整个重构已l结束了Q?我们已经if else, switch完全从代码里剔除了?</span><br id="t4rh" /> <script type="text/javascript"><!-- google_ad_client = "pub-7331426433126513"; /* 728x90, created 7/11/08 */ google_ad_slot = "1570738323"; google_ad_width = 728; google_ad_height = 90; //--> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> <br id="t4rh0" /> <p id="rhi73" class="MsoNormal"><span id="rhi74" lang="EN-GB">读过Refactoring to Patternsq本书的朋友可能会觉得,q里所作的一些和书中W七章最后一节Replace Conditional Dispatcher with Command完全一栗? WellQ第一眼看上去实很像Q但是看完我写的所有代码后Q再仔细想一惻I两者还是有区别的(</span><span id="de57" lang="EN-GB">Refactoring to Patternsq本书写的非常好Q对此书Q我可以说是׃释手Q还曄写过一书评。事实上Q我q篇文章正式Zq本书的Q:</span></p> <p id="q75b2" class="MsoNormal"><span id="q75b3" lang="EN-GB">1. Factory + annonymousc而不是每一个状态一个具体的实体cR?/span></p> <p id="jg36" class="MsoNormal"><span id="jg360" lang="EN-GB">    q样处理问题Q?cȝ数量大大减少Q类兌的复杂程度也大大减少Q维护v来很方便?/span></p> <p id="y13w" class="MsoNormal"><span id="y13w0" lang="EN-GB">2. performerq不单单是一个commandQ它拥有状态,q且可以处理更多的逻辑?/span></p> <br /> 全文完?br /> <img src ="http://www.aygfsteel.com/polygoncell/aggbug/219786.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/polygoncell/" target="_blank">polygoncell</a> 2008-08-04 03:48 <a href="http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219786.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用重构U除丑陋的if else代码Q?Q?/title><link>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219785.html</link><dc:creator>polygoncell</dc:creator><author>polygoncell</author><pubDate>Sun, 03 Aug 2008 19:08:00 GMT</pubDate><guid>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219785.html</guid><wfw:comment>http://www.aygfsteel.com/polygoncell/comments/219785.html</wfw:comment><comments>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219785.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.aygfsteel.com/polygoncell/comments/commentRss/219785.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/polygoncell/services/trackbacks/219785.html</trackback:ping><description><![CDATA[本文紧接<a id="Editor_Results_rprSelectionList_ctl01_LinkTitle" class="titlelink" href="../archive/2008/08/04/219784.html">使用重构U除丑陋的if else代码Q?Q?/a><br /> <br /> <p id="v:wh" class="MsoNormal"><span id="v:wh0" lang="EN-GB">OK, 到目前ؓ止,所有的逻辑代码已经从SystemManager重构CSystemStatePerformer。下一步应该l重构SystemManagerQ?SystemState替换为performerQ?/span></p> <p id="pw4b" class="MsoNormal"><span id="pw4b0" lang="EN-GB">1Q?使用IDE的重构功能,变量SystemState改ؓSystemStatePerformer</span></p> <p id="dz_e" class="MsoNormal"><span id="dz_e0" lang="EN-GB">2. 在updateState()Ҏ中调用SystemStatePerformerFactory</span></p> <span id="hazn0" lang="EN-GB">3. 在测试代码里面,调用manager.statePerformer.getState()</span><br id="nyha1" /> <br id="fljx" /> 重构后的代码如下Q?br /> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;">package</span><span style="color: #000000;"> de.jingge.refactoring;<br /> <br />  <br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> de.jingge.refactoring.SystemState.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br /> </span><span style="color: #000000;"><br /> <br /> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> SystemManager {<br /> <br />  <br /> <br />     SystemStatePerformer statePerformer;<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> login() {<br /> <br />         </span><span style="color: #008000;">//</span><span style="color: #008000;"> call service#login()</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />         updateState(LOGGEDIN);<br /> <br />     }<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> logout() {<br /> <br />         </span><span style="color: #008000;">//</span><span style="color: #008000;"> call service#logout()</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />         updateState(LOGGEDOUT);<br /> <br />     }<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> idle() {<br /> <br />         </span><span style="color: #008000;">//</span><span style="color: #008000;"> call some other services</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />         updateState(IDLE);<br /> <br />     }<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> updateState(SystemState state) {<br /> <br />         </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.statePerformer </span><span style="color: #000000;">=</span><span style="color: #000000;"> SystemStatePerformerFactory.getInstance()<br /> <br />                 getSystemStatePerformer(state);<br /> <br />         statePerformer.perform();<br /> <br />     }<br /> <br /> }</span></div> <br /> 可以看到if else已经消失了?br id="nyha6" /> <br /> <script type="text/javascript"><!-- google_ad_client = "pub-7331426433126513"; /* 728x90, created 7/11/08 */ google_ad_slot = "1570738323"; google_ad_width = 728; google_ad_height = 90; //--> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> <br id="gflh" /> 试代码也要做相应修改:<br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;">package</span><span style="color: #000000;"> de.jingge.refactoring;<br /> <br />  <br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> org.junit.AfterClass;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> org.junit.BeforeClass;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> org.junit.Test;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> org.junit.Assert.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> de.jingge.refactoring.SystemState.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br /> </span><span style="color: #000000;"><br /> <br /> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> SystemManagerTest {<br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> SystemManager manager;<br /> <br />     @BeforeClass<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> setUpClass() </span><span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {<br /> <br />         manager </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SystemManager();<br /> <br />         </span><span style="color: #008000;">//</span><span style="color: #008000;"> add some service mock objects</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />     }<br /> <br />     @AfterClass<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> tearDownClass() </span><span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {<br /> <br />     }<br /> <br />     @Test<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> login() {<br /> <br />         manager.login();<br /> <br />         assertEquals(manager.statePerformer.getState(), LOGGEDIN);<br /> <br />     }<br /> <br />     @Test<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> logout() {<br /> <br />         manager.logout();<br /> <br />         assertEquals(manager.statePerformer.getState(), LOGGEDOUT);<br /> <br />     }<br /> <br />     @Test<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> idle() {<br /> <br />         manager.idle();<br /> <br />         assertEquals(manager.statePerformer.getState(), IDLE);<br /> <br />     }<br /> <br /> }</span></div> <br /> <p id="khlv0" class="MsoNormal"><span id="khlv1" lang="EN-GB">到这里重构已l差不多完成了,代码已经更加面向对象了。这里还有一个小问题Q在factory里面q有一个switchQ这个和if else其实是没有本质区别的Q也是说if elseq没有被完全U除掉?br id="khlv2" /> </span></p> <br id="nb7o0" /> <span id="nb7o3" lang="EN-GB">那么如何能够d把这个switch也移除掉呢?很简单,我们只需要在getSystemStatePerformer()Ҏ被调用之前先创徏所? performer匿名cȝ实例Q然后在该方法被调用时直接返回对应的实力?那么具体如何实现呢,L下一文?/span><a id="PostsList1_rpPosts_ctl00_TitleUrl" href="../archive/2008/08/04/219786.html">使用重构U除丑陋的if else代码Q?Q?/a><span id="nb7o3" lang="EN-GB">?br /> <script type="text/javascript"><!-- google_ad_client = "pub-7331426433126513"; /* 728x90, created 7/11/08 */ google_ad_slot = "1570738323"; google_ad_width = 728; google_ad_height = 90; //--> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> </span> <img src ="http://www.aygfsteel.com/polygoncell/aggbug/219785.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/polygoncell/" target="_blank">polygoncell</a> 2008-08-04 03:08 <a href="http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219785.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用重构U除丑陋的if else代码Q?Q?/title><link>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219784.html</link><dc:creator>polygoncell</dc:creator><author>polygoncell</author><pubDate>Sun, 03 Aug 2008 18:54:00 GMT</pubDate><guid>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219784.html</guid><wfw:comment>http://www.aygfsteel.com/polygoncell/comments/219784.html</wfw:comment><comments>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219784.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.aygfsteel.com/polygoncell/comments/commentRss/219784.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/polygoncell/services/trackbacks/219784.html</trackback:ping><description><![CDATA[本文紧接<a id="Editor_Results_rprSelectionList_ctl01_LinkTitle" class="titlelink" href="../archive/2008/08/04/219781.html">使用重构U除丑陋的if else代码Q?Q?/a><br /> <strong><span style="font-size: 14pt;"><br /> U除if else<br /> </span></strong><br /> <p id="w9yc2" class="MsoNormal"><span id="w9yc3" lang="EN-GB">首先仔细观察一 下updateState()ҎQ我们会发现Q导致该Ҏ内存在大量if else的原因是它的参数仅仅是一个enum。由于enum本nq不含有M逻辑代码Q因此导致处理enum的方法需要用if else来分析enum然后调用相应的逻辑。明白了q个道理之后Q重构的方向明了了。简单的_我们需要要方法参数由enum替换成一个更加强壮的? 象类Q每一个承该cȝ子类具体负责处理一个enum实例Q之后再updateStateQ)Ҏ中相应的逻辑代码转移到这些子cM。这样处理之后, 令h讨厌的if else׃消失了?br id="w9yc4" /> </span></p> <p id="y.bf844" class="MsoNormal"><span id="y.bf845" lang="EN-GB"><br id="hfer" /> </span></p> <span id="hfer1" lang="EN-GB">我们这个替换enum的抽象类命名为SystemStatePerformerQ代码如下:<br /> <br /> </span> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;">package</span><span style="color: #000000;"> de.jingge.refactoring;<br /> <br />  <br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.awt.Image;<br /> </span><span style="color: #000000;"><br /> <br /> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">abstract</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> SystemStatePerformer {<br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">final</span><span style="color: #000000;"> SystemState state;<br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> Image image;<br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> SystemStatePerformer(SystemState state, Image image) {<br /> <br />         </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.state </span><span style="color: #000000;">=</span><span style="color: #000000;"> state;<br /> <br />         </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.image </span><span style="color: #000000;">=</span><span style="color: #000000;"> image;<br /> <br />     }<br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> SystemState getState() {<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> state;<br /> <br />     }<br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Image getImage() {<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> image;<br /> <br />     }<br />     <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">abstract</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> perform();<br /> <br /> }</span></div> <br /> <p id="gaic0" class="MsoNormal"><span id="gaic1" lang="EN-GB">从代码中可以看出Q每 一个performer都含义有一个SystemStateQ这个SystemState属性,只能通过构徏器映方式射入一个performer的对 象实例。换句话说SystemState只是一个只d性,而且每一个performer实体c都只负责处理一个enum的实例(下面马上会解释如何实? 的)。这里用的Image作ؓ一个例子,它表C用L每一个状态都可以使用一个图标来表示。performer()Ҏ负责处理具体的逻辑。这? SystemStatePerformer的实体子cd以引用Q何类型的对象Q然后在performQ)Ҏ里面q行调用?<br id="gaic2" /> </span></p> <br /> <script type="text/javascript"><!-- google_ad_client = "pub-7331426433126513"; /* 728x90, created 7/11/08 */ google_ad_slot = "1570738323"; google_ad_width = 728; google_ad_height = 90; //--> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> <br /> <br id="xwuj" /> <span id="zvtj1" lang="EN-GB">? 一步就是编写SystemStatePerformer的实体子cR我首先惛_的是为每一个enum实例~写一个实际的子类Q理Z来说是没问题的,但是 q样做必ȝ写一大堆的子c,不便于管理。所以我军_使用Factory + annonymous classes来构建具体的实体子类Q让Factory来管理所有的实体子类?/span> 代码如下Q?br id="xwuj0" /> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;">package</span><span style="color: #000000;"> de.jingge.refactoring;<br /> <br />  <br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> de.jingge.refactoring.SystemState.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.awt.Image;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.awt.image.BufferedImage;<br /> </span><span style="color: #000000;"><br /> <br /> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> SystemStatePerformerFactory {<br /> <br />  <br /> <br /> </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> SystemStatePerformerFactory INSTANCE </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SystemStatePerformerFactory();<br /> <br />    <br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> SystemStatePerformerFactory() {<br /> <br /> }<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> SystemStatePerformer getSystemStatePerformer(SystemState state) {<br /> <br />         </span><span style="color: #0000ff;">switch</span><span style="color: #000000;"> (state) {<br /> <br />             </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> LOGGEDIN:<br /> <br />                 </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> createLoggedInPerformer();<br /> <br />             </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> IDLE:<br /> <br />                 </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> createIdlePerformer();<br /> <br />             </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> LOGGEDOUT:<br /> <br />                 </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> createLoggedOutPerformer();<br /> <br />             </span><span style="color: #0000ff;">default</span><span style="color: #000000;">:<br /> <br />                 </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> IllegalAccessError(</span><span style="color: #000000;">"</span><span style="color: #000000;">Unkonw status</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br /> <br />         }<br /> <br />     }<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> SystemStatePerformer createLoggedInPerformer() {<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SystemStatePerformer(LOGGEDIN, getImage(</span><span style="color: #000000;">"</span><span style="color: #000000;">loggedin.gif</span><span style="color: #000000;">"</span><span style="color: #000000;">)) {<br /> <br />  <br /> <br />             @Override<br /> <br />             </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> perform() {<br /> <br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;"> do something after logging in is successful,<br /> <br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;"> for example: show welcome dialog, open the last edit document, etc.</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />             }<br /> <br />         };<br /> <br />     }<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> SystemStatePerformer createLoggedOutPerformer() {<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SystemStatePerformer(LOGGEDOUT, getImage(</span><span style="color: #000000;">"</span><span style="color: #000000;">loggedout.gif</span><span style="color: #000000;">"</span><span style="color: #000000;">)) {<br /> <br />  <br /> <br />             @Override<br /> <br />             </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> perform() {<br /> <br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;"> do something after logging out is successful,<br /> <br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;"> for example: free used resource, dispose GUI components, etc.            }</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />             }<br /> <br />         };<br /> <br />     }<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> SystemStatePerformer createIdlePerformer() {<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SystemStatePerformer(IDLE, getImage(</span><span style="color: #000000;">"</span><span style="color: #000000;">idle.gif</span><span style="color: #000000;">"</span><span style="color: #000000;">)) {<br /> <br />  <br /> <br />             @Override<br /> <br />             </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> perform() {<br /> <br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;"> do something after the user is idle,<br /> <br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;"> for example: save the application state temporarily, lock the application, etc.</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />             }<br /> <br />         };<br /> <br />     }<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> Image getImage(String string) {<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> BufferedImage(</span><span style="color: #000000;">10</span><span style="color: #000000;">, </span><span style="color: #000000;">10</span><span style="color: #000000;">, BufferedImage.TYPE_4BYTE_ABGR);<br /> <br />     }<br /> <br /> }</span></div> <br /> <p id="lvu93" class="MsoNormal"><span id="lvu94" lang="EN-GB">? 代码中可以看刎ͼ针对每一个enum状态都有一个创建performer的方法,该方法返回一个匿名类。逻辑代码会被{U至个匿名类? perform()Ҏ之内。整个Factory只有一个公开的方 法:getSystemStatePerformer(SystemState)QSystemManager可以调用q个Ҏ来获得相应的 Performer实例?br id="lvu95" /> </span></p> <br /> <span id="aofb3" lang="EN-GB">? q篇文章中,我希望专属于if else的问题。对于其他设计方面的问题Q我采取的态度是能省略q略。实际开发中Q还有有很多问题需要处理,例如Q用staticҎ会导致系l的? 试性下降,在实际开发中应该量避免Q解册c问题的Ҏ之一是用DI框架Q例如Google Guice?/span><br /> <br /> 下一文?a id="Editor_Results_rprSelectionList_ctl01_LinkTitle" class="titlelink" href="../archive/2008/08/04/219785.html">使用重构U除丑陋的if else代码Q?Q?/a>l箋讲解?br /> <script type="text/javascript"><!-- google_ad_client = "pub-7331426433126513"; /* 728x90, created 7/11/08 */ google_ad_slot = "1570738323"; google_ad_width = 728; google_ad_height = 90; //--> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> <img src ="http://www.aygfsteel.com/polygoncell/aggbug/219784.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/polygoncell/" target="_blank">polygoncell</a> 2008-08-04 02:54 <a href="http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219784.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用重构U除丑陋的if else代码Q?Q?/title><link>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219781.html</link><dc:creator>polygoncell</dc:creator><author>polygoncell</author><pubDate>Sun, 03 Aug 2008 18:45:00 GMT</pubDate><guid>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219781.html</guid><wfw:comment>http://www.aygfsteel.com/polygoncell/comments/219781.html</wfw:comment><comments>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219781.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/polygoncell/comments/commentRss/219781.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/polygoncell/services/trackbacks/219781.html</trackback:ping><description><![CDATA[本文紧接<a id="Editor_Results_rprSelectionList_ctl01_LinkTitle" class="titlelink" href="../archive/2008/08/04/219780.html">使用重构U除丑陋的if else代码Q?Q?/a>?br /> <br /> <strong>使用Enum替换int帔R</strong><br /> <br /> q一步比较简单,先创Z个enumc:<br /> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;">package</span><span style="color: #000000;"> de.jingge.refactoring;<br /> <br /> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">enum</span><span style="color: #000000;"> SystemState {<br /> <br />     LOGGEDIN,<br /> <br />     LOGGEDOUT,<br /> <br />     IDLE;<br /> <br /> }</span></div> <br /> <br id="i7km192" /> 然后开始重构SystemManager, 使用SystemState代替SystemManager里的int状态:<br id="i7km193" /> <br id="i7km194" />    1. d import static de.jingge.refactoring.SystemState.*;<br id="i7km195" />    2. 删除所有的integer帔R   <br id="i7km196" />    3. 变量state的类型改为SystemState.<br id="i7km197" /> <br id="i7km198" /> 代码如下Q?br /> <br /> <script type="text/javascript"><!-- google_ad_client = "pub-7331426433126513"; /* 728x90, created 7/11/08 */ google_ad_slot = "1570738323"; google_ad_width = 728; google_ad_height = 90; //--> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> <br /> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;">package</span><span style="color: #000000;"> de.jingge.refactoring;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> de.jingge.refactoring.SystemState.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br /> <br /> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> SystemManager {<br /> <br />     SystemState state;<br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> login() {<br />         </span><span style="color: #008000;">//</span><span style="color: #008000;"> call service#login()</span><span style="color: #008000;"><br /> </span><span style="color: #000000;">        updateState(LOGGEDIN);<br />     }<br />    <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> logout() {<br />         </span><span style="color: #008000;">//</span><span style="color: #008000;"> call service#logout()</span><span style="color: #008000;"><br /> </span><span style="color: #000000;">        updateState(LOGGEDOUT);<br />     }<br />    <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> idle() {<br />         </span><span style="color: #008000;">//</span><span style="color: #008000;"> call some other services</span><span style="color: #008000;"><br /> </span><span style="color: #000000;">        updateState(IDLE);<br />     }<br />    <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> updateState(SystemState state) {<br />         </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (state </span><span style="color: #000000;">==</span><span style="color: #000000;"> LOGGEDIN) {<br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> do something after logging in is successful,<br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> for example: show welcome dialog, open the last edit document, etc.</span><span style="color: #008000;"><br /> </span><span style="color: #000000;">        } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (state </span><span style="color: #000000;">==</span><span style="color: #000000;"> LOGGEDOUT) {<br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> do something after logging out is successful,<br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> for example: free used resource, dispose GUI components, etc.</span><span style="color: #008000;"><br /> </span><span style="color: #000000;">        } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (state </span><span style="color: #000000;">==</span><span style="color: #000000;"> IDLE) {<br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> do something after the user is idle,<br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> for example: save the application state temporarily, lock the application, etc.</span><span style="color: #008000;"><br /> </span><span style="color: #000000;">        } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {<br />             </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> IllegalArgumentException(</span><span style="color: #000000;">"</span><span style="color: #000000;">unknown state</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />         }<br />         </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.state </span><span style="color: #000000;">=</span><span style="color: #000000;"> state;<br />     }<br /> }<br /> </span></div> <br /> 然后重构试c?<br id="i7km244" /> <br id="i7km245" /> 1.    dimport static de.jingge.refactoring.SystemState.*;<br id="i7km246" /> 2.    删除所有常量前引用的SystemManager.<br id="i7km247" /> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;">package</span><span style="color: #000000;"> de.jingge.refactoring;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> org.junit.AfterClass;<br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> org.junit.BeforeClass;<br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> org.junit.Test;<br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> org.junit.Assert.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> de.jingge.refactoring.SystemState.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br /> <br /> </span><span style="color: #000000;"><br /> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> SystemManagerTest {<br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> SystemManager manager;<br /> <br />     @BeforeClass<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> setUpClass() </span><span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {<br />         manager </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SystemManager();<br />         </span><span style="color: #008000;">//</span><span style="color: #008000;"> add some service mock objects</span><span style="color: #008000;"><br /> </span><span style="color: #000000;">    }<br />    <br />     @AfterClass<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> tearDownClass() </span><span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {<br />     }<br />    <br />     @Test<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> login() {<br />         manager.login();<br />         assertEquals(manager.state, LOGGEDIN);<br />     }<br />   <br />     @Test<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> logout() {<br />         manager.logout();<br />         assertEquals(manager.state, LOGGEDOUT);<br />     }<br /> <br />     @Test<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> idle() {<br />         manager.idle();<br />         assertEquals(manager.state, IDLE);<br />     }<br /> }<br /> </span></div> <br /> <br id="ja7w" /> q行q个试c?>通过<br id="ja7w0" /> <br id="ja7w1" /> 下一文?a id="Editor_Results_rprSelectionList_ctl01_LinkTitle" class="titlelink" href="../archive/2008/08/04/219784.html">使用重构U除丑陋的if else代码Q?Q?/a>开始处理if else hell<br /> <script type="text/javascript"><!-- google_ad_client = "pub-7331426433126513"; /* 728x90, created 7/11/08 */ google_ad_slot = "1570738323"; google_ad_width = 728; google_ad_height = 90; //--> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> <img src ="http://www.aygfsteel.com/polygoncell/aggbug/219781.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/polygoncell/" target="_blank">polygoncell</a> 2008-08-04 02:45 <a href="http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219781.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用重构U除丑陋的if else代码Q?Q?/title><link>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219780.html</link><dc:creator>polygoncell</dc:creator><author>polygoncell</author><pubDate>Sun, 03 Aug 2008 18:36:00 GMT</pubDate><guid>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219780.html</guid><wfw:comment>http://www.aygfsteel.com/polygoncell/comments/219780.html</wfw:comment><comments>http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219780.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.aygfsteel.com/polygoncell/comments/commentRss/219780.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/polygoncell/services/trackbacks/219780.html</trackback:ping><description><![CDATA[我们知道因ؓ~程语言的限Ӟ历史遗留下来的系lL有很多的毛病Q不够面向对象,其是很多系l滥用if else。我曄见过一个项目,大家基本上就是写一个方法,然后在里面if else套if esle得嵌套了好几层,隄׃必说了,q种代码Ҏ没法维护?br id="i7km" /> <br id="i7km0" /> 今天我就使用从实际项目中提炼出来的例子来讲解一下如何将q类代码变得更加面向对象 - 重构成模式ƈ且添加测试代码, <br id="i7km1" /> <br id="i7km2" /> 先来看一个丑陋的c:<br /> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;">package</span><span style="color: #000000;"> de.jingge.refactoring;<br /> <br />  <br /> <br /> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> SystemManager {<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> </span><span style="color: #0000ff;">final</span><span style="color: #000000;"> </span><span style="color: #0000ff;">int</span><span style="color: #000000;"> LOGGEDIN </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">0</span><span style="color: #000000;">;<br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> </span><span style="color: #0000ff;">final</span><span style="color: #000000;"> </span><span style="color: #0000ff;">int</span><span style="color: #000000;"> LOGGEDOUT </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">1</span><span style="color: #000000;">;<br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> </span><span style="color: #0000ff;">final</span><span style="color: #000000;"> </span><span style="color: #0000ff;">int</span><span style="color: #000000;"> IDLE </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">2</span><span style="color: #000000;">;<br /> <br />     </span><span style="color: #0000ff;">int</span><span style="color: #000000;"> state;<br /> <br />  <br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> login() {<br /> <br />         </span><span style="color: #008000;">//</span><span style="color: #008000;"> call service#login()</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />         updateState(LOGGEDIN);<br /> <br />     }<br /> <br />    <br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> logout() {<br /> <br />         </span><span style="color: #008000;">//</span><span style="color: #008000;"> call service#logout()</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />         updateState(LOGGEDOUT);<br /> <br />     }<br /> <br />    <br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> idle() {<br /> <br />         </span><span style="color: #008000;">//</span><span style="color: #008000;"> call some other services</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />         updateState(IDLE);<br /> <br />     }<br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> updateState(</span><span style="color: #0000ff;">int</span><span style="color: #000000;"> state) {<br /> <br />         </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (state </span><span style="color: #000000;">==</span><span style="color: #000000;"> LOGGEDIN) {<br /> <br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> do something after logging in is successful,<br /> <br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> for example: show welcome dialog, open the last edit document, etc.</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />         } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (state </span><span style="color: #000000;">==</span><span style="color: #000000;"> LOGGEDOUT) {<br /> <br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> do something after logging out is successful,<br /> <br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> for example: free used resource, dispose GUI components, etc.</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />         } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (state </span><span style="color: #000000;">==</span><span style="color: #000000;"> IDLE) {<br /> <br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> do something after the user is idle,<br /> <br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> for example: save the application state temporarily, lock the application, etc.</span><span style="color: #008000;"><br /> </span><span style="color: #000000;"><br />         } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {<br /> <br />             </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> IllegalArgumentException(</span><span style="color: #000000;">"</span><span style="color: #000000;">unknown state</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br /> <br />         }<br /> <br />         </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.state </span><span style="color: #000000;">=</span><span style="color: #000000;"> state;<br /> <br />     }<br /> <br /> }</span></div> <br /> <script type="text/javascript"><!-- google_ad_client = "pub-7331426433126513"; /* 728x90, created 7/11/08 */ google_ad_slot = "1570738323"; google_ad_width = 728; google_ad_height = 90; //--> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> <br /> q里我们展示了一?SystemManagerQ它负责处理用户在系l中的状态:dQlogged inQ,dQlogged outQ?以及I闲QidleQ。从代码中可以看刎ͼq个cȝ了int来定义状态ƈ且因此导致了updatteStateQ)Ҏ里面出现大量if else。从目前看来q些if else是无法避免的Q应个类需要针对不同的状态作出反应。随着状态的增加Qif else的数量也会l增加。这个解x案显然很差?br id="i7km87" /> <br id="i7km88" /> 那么怎么h能让q个cL加地面向对象呢?<br id="i7km89" /> <br id="i7km90" /> 在处理面向对象之前,我们首先要编写一个测试类Q这也是处理q类历史遗留下来代码所必需做的W一步,只有在测试代码的保护下,我们才能攑ֿ大胆地进行重构?br id="i7km91" /> <br id="i7km92" /> 初步的测试代码如下:<br /> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;">package</span><span style="color: #000000;"> de.jingge.refactoring;<br /> <br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> org.junit.AfterClass;<br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> org.junit.BeforeClass;<br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> org.junit.Test;<br /> </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> org.junit.Assert.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br /> <br /> </span><span style="color: #000000;"><br /> <br /> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> SystemManagerTest {<br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> SystemManager manager;<br /> <br />     @BeforeClass<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> setUpClass() </span><span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {<br />         manager </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SystemManager();<br />         </span><span style="color: #008000;">//</span><span style="color: #008000;"> add some service mock objects</span><span style="color: #008000;"><br /> </span><span style="color: #000000;">    }<br /> <br />     @AfterClass<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> tearDownClass() </span><span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {<br /> <br />     }<br /> <br />     @Test<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> login() {<br /> <br />         manager.login();<br /> <br />         assertEquals(manager.state, SystemManager.LOGGEDIN);<br /> <br />     }<br /> <br />     @Test<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> logout() {<br /> <br />         manager.logout();<br /> <br />         assertEquals(manager.state, SystemManager.LOGGEDOUT);<br /> <br />     }<br /> <br />     @Test<br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> idle() {<br /> <br />         manager.idle();<br /> <br />         assertEquals(manager.state, SystemManager.IDLE);<br /> <br />     }<br /> <br /> }</span></div> <br /> q行试代码->通过?br id="i7km171" /> <br id="i7km172" /> 在下一文章我们将正式开始重构。地址Q?a title="使用重构U除丑陋的if else代码Q?Q? target="_blank" href="http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219781.html">使用重构U除丑陋的if else代码Q?Q?/a><br /> <script type="text/javascript"><!-- google_ad_client = "pub-7331426433126513"; /* 728x90, created 7/11/08 */ google_ad_slot = "1570738323"; google_ad_width = 728; google_ad_height = 90; //--> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> <img src ="http://www.aygfsteel.com/polygoncell/aggbug/219780.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/polygoncell/" target="_blank">polygoncell</a> 2008-08-04 02:36 <a href="http://www.aygfsteel.com/polygoncell/archive/2008/08/04/219780.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>书评Q?Refactoring to Patternhttp://www.aygfsteel.com/polygoncell/archive/2008/07/29/218513.htmlpolygoncellpolygoncellTue, 29 Jul 2008 11:17:00 GMThttp://www.aygfsteel.com/polygoncell/archive/2008/07/29/218513.htmlhttp://www.aygfsteel.com/polygoncell/comments/218513.htmlhttp://www.aygfsteel.com/polygoncell/archive/2008/07/29/218513.html#Feedback0http://www.aygfsteel.com/polygoncell/comments/commentRss/218513.htmlhttp://www.aygfsteel.com/polygoncell/services/trackbacks/218513.html
最q阅ȝ书ƈ不都是最新的Q因Z书的是需要花旉反复研读Q仔l思考的Q例如关于设计模式的书?br id="tt2t" />
Refactoring to Patterns是q样一本书Q一本相Ҏ说不太新的书,一本关于设计模式的书,一本让Z新开始思考模式的书。我本h强烈推D大家阅读?br id="x6op" />
q本书刚出来的时候,我就一直想好好静下心来M读,无奈工作忙碌Q一直没有找到机会。而且说实话,自己对设计模式也已经淫数蝲Q大部分模式都已l在? 际项目中历练q,不说炉火U青Q也得上是熟能生y。虽然知道这是一本好书,但是心里依然会泛起阵阉|漪:just another design pattern bookQ给我一天时_我就能把它拿下。没惛_从开始读到现在已l?个多月了Q现在依然会抽时间出来翻看某个章节,然后l合实际问题仔细思考一番。说? 话,设计模式真的是个好东西,是前辈经验的U篏Q但是当我们熟练掌握了各U模式之后,׃遇到两个瓉性质的问题:

1. 如何各cL式融汇诏通。感觉就像是武侠里面的如何将ȝ二脉打通,功夫再好QQ督二脉不通也非高手,不同的模式相互作用会产生不同的结果,不同的模式组合会产生不同的结构,或相互补充相互促q,或互相媄响互相抵制。如何选择Q是个难题?br id="ifwv" />
2. 如何避免q度设计。模式用熟的朋友可能会有q种感觉Q编E的时候会不知不觉中用模式进行开发,模式再好Q泛滥用,q犹不及。好像武功一般,招式J多Q固然耍v来好看,但是高手最后的境界往往是无招胜有招Q只要能目的辑ֈp了?br id="i:83" />
W一个问题由于模式之间的l合千变万化Q而且很多需要结合实际问题进行考虑Q大家只能是在实际项目开发中慢慢体会Q慢慢积累经验。或许再q几q会有某个h或者某些h把这些经验收集整理,~排Z?br id="p99i" />
今天主要惌说第二个问题Q过度设计?Refactoring to Patternsq本书就是帮助我们尽量避免过度设计的Q这也是我推荐大家看q本书的初衷?br id="jar4" />
事实上,q本书完全可以看成是极限~程pd里面的一部巨头著作,其他的重要著作包括TDDQRefactoringQ和continuous integrationQ合h应该UCؓXP四大金刚?br id="f4g2" />
使用XP开发强调keep it simpleQ在~码的时候首先用最单的办法实现功能(当然最好是试驱动,我会在评Z面一本书是l谈试驱动Q,然后在测试代码的保护下对初? 码进行大刀阔斧地重构,q时候这些代码自然最好能够重构成设计模式Q因为针Ҏ些特定的问题Q模式基本上是最佌x案。这个时候就大家需要了解如何将 现有的代码重构成为标准的设计模式代码Q说的严重点Q这一步关pd整个代码的质量,直至引申到真个项目的质量。这本书针对这个关键步骤进行了讲解Q是所 有采用XPҎ的开发团队的必修课之一?br id="w11_" />

至于书的内容我就量单概括一下:本书基本上覆盖了重构目中会遇到的大部分问题Qƈ且针对这些问题提供了实例讲解和具体的解决Ҏ。这些方案不单单? 用于使用TDD开发的目Q它们更适用于那些希望通过重构改善现有代码质量的项目。当Ӟ重构前,千万别尝试避开~写试代码Q要牢记Q没有测试代码保 护,最好不要对代码做大手术。书中的很多例子都值得大家d以后l合自己的实际项目仔l思考一番。我个h很喜Ƣ第7章,已经在项目中采用了书中提到的很多 解决ҎQƈ且对于某些实际例子,开始尝试优化书中的ҎQ希望以后能够抽出时间来写一详l的博文?

polygoncell 2008-07-29 19:17 发表评论
]]>
Swing通用数据验证模块http://www.aygfsteel.com/polygoncell/archive/2008/07/29/218508.htmlpolygoncellpolygoncellTue, 29 Jul 2008 10:27:00 GMThttp://www.aygfsteel.com/polygoncell/archive/2008/07/29/218508.htmlhttp://www.aygfsteel.com/polygoncell/comments/218508.htmlhttp://www.aygfsteel.com/polygoncell/archive/2008/07/29/218508.html#Feedback5http://www.aygfsteel.com/polygoncell/comments/commentRss/218508.htmlhttp://www.aygfsteel.com/polygoncell/services/trackbacks/218508.html q段旉真是忙得要死Q一斚w要开发公叔R目的pȝ框架Q要项目分成不同的子项目,~写核心代码Q另一斚w要将极限~程QXPQ引入团队开发,部v各类 XP需要的服务例如subversion啦,ant+ivy啦,Hudson啦等{。顺便说句题外话Qubuntuq真是不是一般的好用Q徏议有能力的全 部{到ubuntu上去开发?

我目前开发的q个框架的客L是具肥的客户端,也就是Swing客户端了。Swing应用相对于Web应用有很多优势,因ؓ它更肥。数据验证就? 其中一个。当然现在的Web应用通过使用Ajax也要比以前强很多了,但是q是避免不了在验证数据时向服务段发出hQ至你无法避免验证l果从Web? 务器传输到用h览器上这D过E。而Swingq类肥客L可以实现完全在本地对数据q行验证Q甚臛_以断|l工作(q也是Web应用目前在研发的一? 重要NQ?

前段旉开发出了一个可以应用于所有Swing应用的通用数据验证模块Q发现它在项目中使用后,对于普通的数据验证,E序员几乎不需要编码,效率提高了不,写了一博文拿出来和大家分享。原文是用英文写的,在这里:http://polygoncell.blogspot.com/2008/07/validation-module-for-swing-application.html。英文好的朋友可以直接去那里看?

~写q个模块使用了很多不同的开源框架和cdQ其中很重要的一个就是JXLayer。文章写完后Q我p去邀请JXLayer的作者Alexp来指点一下,然后在我的文章后面开始了一D讨论,挺有意思的Q他不愧为是Swing team里面的牛人啊Q厉宛_Q呵c?

okQ回C天这文章的正题。今天的主要目的是将我的英文博文译成中文(自己的文章,我就不逐字逐句译了,意思到了就行了Q可能还会随兴展 开一番讨论)在这里展C给大家Q与大家分n开发经验,希望大家能够从中LQ也希望能够以文会友Q广交朋友。废话少_切入正题?

数据验证QValidationQ一直是软g开发中非常重要的一环,有了它,你的pȝ会让客户感到更加友善Q同时你的系l也得到了一定程度的? 护。一般来_数据验证既可以在客户端也可以在服务端。默认的JSF数据验证是在服务端Q数据只能在被提交以后才能够被验证,然后把错误信息传递回用户 的浏览器。后来大规模使用Ajax后,基本可以实现对修改的数据“x”验证Q注意这里是个打了引LxQ数据事实上q是要在览器和服务端之间进行传 递的Q只不过Ajax这U传递改为隐式了而已Q理Zq没有真正实玎ͼ断网Q即旉证。而在Swing应用上就能够达成q种愿望?

事实上,开发Swing应用Ӟ数据验证一直比较棘手,需要手工编码的地方太多Q效率不高。后来出了JGoodies Validation l合JGoodies binding后,好了一些。这个JGoodies Validation既可以实现model层面的验证,也可以实现Bean层面的验证,但是多年使用下来Q发现其实它比较适用于中项目,而且要编写的? 码其实一点不比自己手动编写的?

JGoodies行了一D|间后Qsun开始推qbeanl定ҎQbeansbindingQJSR 295Q,我个人感觉要比JGoodies binding好用QJGoodies的作者Karsten也在专家l里Q这个h我以前和他一起共事过Q我的msn space里面q有跟他的合影,l对是Swing界的牛hQ。这个beansbinding也提供数据验证,但是它的q个数据验证只是在target被改 动后Q数据被同步回source之前才会起作用,使用h局限性比较大Q而且~码量也不小?

׃目前l大部分目是基于POJO的,Hibernate validator已经提供了一个很好的数据验证框架Q我们完全没必要再重复发明轮子,我们应该努力站在巨h的肩膀上,q样我们才能站得更高Q看得更q? 于是我考虑l合beansbinding和Hibernate Validator开发数据验证。还有一个重要的问题Q那是数据错误的时候,需要在用户界面上展C相应的信息Q例如Error icon和错误提C,q部分我考虑使用JXLayer?

你可以在如下链接中找到相x架的具体信息Q?

1. Hibernate ValidatorQ?http://www.hibernate.org/hib_docs/validator/reference/en/html_single/
2. Beansbinding: https://beansbinding.dev.java.net/
3. JXlayer: http://weblogs.java.net/blog/alexfromsun/

阅读q篇文章Q不需要你熟悉q些cdQ不q了解这些类库能够帮助你更好地理解这文章?

我的q个通用模块是参考JXLayer里面的一个democTextValidationDemo的,q个JXlayer是由Alexander Potochkin开发的Q我很喜Ƣ,使用h很顺手,强烈推荐使用?

下面开始介l代码。首先是建立一个java目Q对于这个小目Q我使用netbeans。这里说句题外话Q中型和大型的Swing应用Q徏议最 好还是不要用netbeans的GUI BuilderQ一斚w它生成的代码烂,另一斚w很难试。目前市面上有很多好用的layout的框Ӟ例如 JGoodies form和MigLayoutQ开发效率绝对不比netbeans的GUI builder差,你还不需要面对o人头疼的机器成的代码?

目创徏好后Q加入类库:



然后写一个persistence bean:
package de.jingge.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import org.hibernate.validator.Length;
import org.hibernate.validator.NotEmpty;


@Entity
public class Country extends AbstractBean {

private static final long serialVersionUID = 5341382564159667599L;
public static final String PROPERTYNAME_NAME = "name";
public static final String PROPERTYNAME_CODE = "code";
private String name;
private String code;
private Long id;

public Country() {
}

public Country(String code, String name) {
    
super();
    setCode(code);
    setName(name);
}

@Id
@GeneratedValue(strategy 
= GenerationType.AUTO)
public Long getId() {
    
return id;
}

public void setId(Long id) {
    
this.id = id;
}

@NotEmpty
public String getName() {
    
return name;
}

public void setName(String name) {
    firePropertyChange(PROPERTYNAME_NAME, 
this.name, this.name = name);
}

@Length(min
=2, max= 2, message="Code length must be 2")
@NotEmpty
public String getCode() {
    
return code;
}

public void setCode(String code) {
    firePropertyChange(PROPERTYNAME_CODE, 
this.code, this.code = code);
}
}


q里我ؓ了强调可以在Swing客户端直接用和验证persistence beanQ故意写了一个persistence beanQ实际应用中Q这个类只需要是一个pojop了?

q个CountrycM表一个国Ӟ它有两个属性,code和nameQ我l他们分别加上个各自的验证限制。code不能为空Q且必须正好是两? 字符Q例如CNQDEQUS。name不能为空。这些annotaion均出自Hibernate Validator。那个父cAbstractBeanSwingXcdQ我们的Countrycȝ承了它之后就可以支持property change event了?

ok, 下面可以开始编写这个模块的核心代码了。前面说q,我会使用JXlayer。用它的好处是Q所有JXlayer的painting event都会被{到UIcLQ我们只需要编写一个集成Hibernate Validator的UIcd可以了,我称q个cMؓHibernateValidationUIQ代码如下:

package de.jingge.view;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.text.JTextComponent;

import org.hibernate.validator.ClassValidator;
import org.hibernate.validator.InvalidValue;
import org.jdesktop.beansbinding.ELProperty;
import org.jdesktop.beansbinding.PropertyStateEvent;
import org.jdesktop.beansbinding.PropertyStateListener;
import org.jdesktop.jxlayer.JXLayer;
import org.jdesktop.jxlayer.plaf.AbstractLayerUI;

/**
* Header:
* Description: A layerUI which will validate the referenced property value of
* the object each time when the paint() method is called.

* The value of the given object property will be observed.
* Note: This UI works only with {
@link JXLayer}. Any change of the property
* will force repainting the UI. The work process looks like: property changed ->
* jxlayer will be repainted -> the paint() method of this UI will be called.
* The logic of validation will be handled by the Hibernate validator
* framework.
*
*/
public class HibernateValidationUI extends AbstractLayerUI<jTextComponent> {

private Object object;
private String propertyName;
private ClassValidator validator;
private ELProperty elProperty;
private PropertyStateListener propertyChangeHandler;

public HibernateValidationUI(Object obj, String propertyName) {
    
this.object = obj;
    
this.propertyName = propertyName;
    propertyChangeHandler 
= new PropertyChangeHandler();
    validator 
= new ClassValidator(obj.getClass());

    elProperty 
= ELProperty.create("${" + propertyName + "}");
}

public void installUI(JComponent c) {
    
super.installUI(c);
    elProperty.addPropertyStateListener(object, propertyChangeHandler);
}

public void uninstallUI(JComponent c) {
    
super.uninstallUI(c);
    elProperty.removePropertyStateListener(object, propertyChangeHandler);
}

protected void paintLayer(Graphics2D g2, JXLayer<jTextComponent> l) {
    
super.paintLayer(g2, l);
    InvalidValue[] validationMessages 
= validator.getInvalidValues(object,
            propertyName);
    
if (validationMessages.length > 0) {
        BufferedImage image 
= Java2DIconFactory.createErrorIcon();
        g2.drawImage(image, l.getWidth() 
- image.getWidth() - 1,
                l.getHeight() 
- 8null);
        l.getView().setToolTipText(validationMessages[
0].getMessage());

        
return;
    }
    l.getView().setToolTipText(
null);
}

boolean isValid() {
    
return validator.getInvalidValues(object, propertyName).length == 0;
}

class PropertyChangeHandler implements PropertyStateListener {

    @Override
    
public void propertyStateChanged(PropertyStateEvent pse) {
        setDirty(
true);
    }
}
}



q个HibernateValidationUIcd有一个构建器Q它接收两个参数Q一个是source objectQ也是我们要修改的那个Beancȝ实例Q另外一个是q个bean的一个属性,q个HibernateValidationUIp责验证这个属性?

在installUI()Ҏ中,我们启动对属性变化的观察c,而在uninstallUI()Ҏ里面Q我们需要卸载这个观察类?

当给定对象的属性值发生变化时QPropertyChangeHandler的propertyStateChangedQ)Ҏ׃被调用,q? 个功能是通过elProperty和PropertzChangeHandler相结合来实现的。在propertyStateChangeed()Ҏ 里UIcȝҎsetDirty()会被调用Q该Ҏ的调用会DUIcȝ状态变化,q而引?re)paintingQ之后经q一pd的方法调用传 递,paintLayer(Graphics2D g2, JXLayer<jTextComponent> l)q个Ҏ会被调用,q个Ҏ要做的就是我们这个数据验证模块的核心功能Q?

1. 调用Hibernate Validator验证该属性?
2. 如果数据不正,则在GUI上显CZ个error iconQƈ且将错误信息作ؓtooltip展示l用戗?

在第二点里面产生了一个问题,谢谢AlexpҎ的指炏VSwing team里面有一些规定,其中之一是Q在paint()Ҏ里面最好不要改变Component的状态,而setTooltip()Ҏ会改变 component的状态,因此需要在paint()Ҏ之外调用。我目前使用下来Q还没有发现什么严重的错误Q决定暂时不改了Q回头有旉在将q个代码 L一下?

cM用到的Java2DIconFactory代码如下Q?

package de.jingge.view;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;


public class Java2DIconFactory {

public static BufferedImage createErrorIcon() {
    
return createErrorIcon(78);
}

public static BufferedImage createErrorIcon(int width, int height) {
    BufferedImage icon 
= new BufferedImage(width, height,
            BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 
= (Graphics2D) icon.getGraphics();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
            RenderingHints.VALUE_STROKE_PURE);
    g2.setColor(Color.RED);
    g2.fillRect(
00, width, height);
    g2.setColor(Color.WHITE);
    g2.drawLine(
00, width, height);
    g2.drawLine(
0, height, width, 0);
    g2.dispose();
    
return icon;
}
}


没什么太多好解释的,是使用Java 2DM个Error icon?

接着Q我们需要编写一个Factoryc,构徏一个JTextFieldQ尽量把复杂技术封装v来,q样E序员开发v来可以提高效率,代码如下Q?

package de.jingge.view;

import javax.swing.JTextField;
import javax.swing.text.JTextComponent;
import org.jdesktop.beansbinding.AutoBinding;
import org.jdesktop.beansbinding.BeanProperty;
import org.jdesktop.beansbinding.BindingGroup;
import org.jdesktop.beansbinding.Bindings;
import org.jdesktop.beansbinding.ELProperty;
import org.jdesktop.jxlayer.JXLayer;
import static org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.*;


public class GuiComponentFactory {

public static JXLayer<jTextComponent> createTextField(
        BindingGroup bindingGroup, Object sourceObject,
        String sourceProperty) {
    JTextField field 
= new JTextField();
    AutoBinding binding 
= Bindings.createAutoBinding(READ_WRITE,
            sourceObject, ELProperty.create(
"${" + sourceProperty + "}"),
            field, BeanProperty.create(
"text"));
    bindingGroup.addBinding(binding);
    bindingGroup.bind();
    
return new JXLayer<jTextComponent>(field, new HibernateValidationUI(
            sourceObject, sourceProperty));
}
}


createTextField()Ҏ主要给定对象属性的gJTextField的textl定Q然后将JTextFieldU_? JXLayer的管理之下。这样一来,一旦用户在JTextField里面修改数据Q这个改变就会同步到该对象属性上Q然后就引发了前面描q的一pd? 辑,最l改变的数据׃被Hiberante Validator加以验证?

最后,我们可以~写一个Demo application来看看效果如何,代码如下Q?

package de.jingge.main;

import de.jingge.domain.Country;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.JTextComponent;
import net.miginfocom.swing.MigLayout;
import org.jdesktop.beansbinding.BindingGroup;
import org.jdesktop.jxlayer.JXLayer;
import static de.jingge.view.GuiComponentFactory.*;


public class ValidationApplicaton {

private BindingGroup bg;
private Country country;
private JXLayer<jTextComponent> codeField;
private JXLayer<jTextComponent> nameField;

/**
 * 
@param args the command line arguments
 
*/
public static void main(String[] args) {
    
try {
        UIManager.setLookAndFeel(
                
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
    } 
catch (UnsupportedLookAndFeelException ex) {
        System.err.println(
                
"Nimbus L&F does not support. Default L&F will be used.");
    } 
catch (ClassNotFoundException e) {
        
// TODO Auto-generated catch block
        e.printStackTrace();
    } 
catch (InstantiationException e) {
        
// TODO Auto-generated catch block
        e.printStackTrace();
    } 
catch (IllegalAccessException e) {
        
// TODO Auto-generated catch block
        e.printStackTrace();
    }
    ValidationApplicaton app 
= new ValidationApplicaton();
    JFrame frame 
= new JFrame("Demo Validation Application");
    frame.setPreferredSize(
new Dimension(360150));
    frame.getContentPane().add(app.buildPanel(), BorderLayout.CENTER);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setCenter(frame);
    frame.setVisible(
true);
    frame.pack();

}

private static void setCenter(JFrame frame) {
    Toolkit toolkit 
= Toolkit.getDefaultToolkit();
    Dimension screenSize 
= toolkit.getScreenSize();

    
// Calculate the frame location
    int x = (screenSize.width - (int) frame.getPreferredSize().getWidth()) / 2;
    
int y = (screenSize.height - (int) frame.getPreferredSize().getHeight()) / 2;

    
// Set the new frame location
    frame.setLocation(x, y);
}

public ValidationApplicaton() {
    country 
= new Country();
    bg 
= new BindingGroup();
}

private JPanel buildPanel() {

    codeField 
= createTextField(bg, country, Country.PROPERTYNAME_CODE);
    nameField 
= createTextField(bg, country, Country.PROPERTYNAME_NAME);
    JPanel panel 
= new JPanel(new MigLayout("",
            
"[50px, right]10[200px:250px:300px]""[center]"));
    panel.add(
new JLabel("Code:"), "cell 0 0");
    panel.add(codeField, 
"cell 1 0, w 200px:250px:300px");
    panel.add(
new JLabel("Name:"), "cell 0 1");
    panel.add(nameField, 
"cell 1 1, w 200px:250px:300px");
    
return panel;
}
}


q个cL较简单了Q我单解释一下:

在main()Ҏ里面Q我们创Z一个JFrameQ然后放入一个JPanel

setCenter()Ҏ负责窗口至于屏q的正中间?

在构建器里面Q我们创ZCountry和BindingGroup的对象实例?

在buildPanel()Ҏ里面Q我们用MigLayout构徏了一个PanelQ其中codeField和nameField对应各自的对象属性。更多关于MigLayout的信息看q里Q?a target="_blank">http://www.miglayout.com/。这也是一个例子,大家可以看到使用MigLayout开发Swing真的是非常方ѝ?

从这个Demo里面也可以看出,~写好pojo后,E序员只需要调用createTextField(bg, country, Country.PROPERTYNAME_CODE); 可以创Z个支持数据验证的JTextFieldQ编码量已经可以说是最大限度的降低了?

q行E序Q你会看刎ͼ



q个code和name的数据都不合法,用户看到了error icon?

鼠标移到Text field上,你会看到Q?



填好合法数据后,Error icon׃见了Q?



ȝQ?

使用q个通用数据验证模块有很多好处:

1. 如果目使用ORMQ例如HibernateQ这个方案应该是解决数据验证的最好方案之一?
2. 对于普通的数据验证Q例如非I,emailQ长度等{,E序员根本不需要编码,只要在POJO上用相应的Hibernate Validator annotation可以了?
3. 对于复杂的数据验证,Hibernate Validator提供了很好的扩展机制Q只要写一个annotation外加一个Validator可以了。Swing应用q边仍然不需要编写Q何代码?

lg所qͼ可以看出通过使用q个通用数据验证模块Q开发效率会提高很多?


polygoncell 2008-07-29 18:27 发表评论
]]>
customer enumhttp://www.aygfsteel.com/polygoncell/archive/2008/03/29/189386.htmlpolygoncellpolygoncellFri, 28 Mar 2008 16:58:00 GMThttp://www.aygfsteel.com/polygoncell/archive/2008/03/29/189386.htmlhttp://www.aygfsteel.com/polygoncell/comments/189386.htmlhttp://www.aygfsteel.com/polygoncell/archive/2008/03/29/189386.html#Feedback0http://www.aygfsteel.com/polygoncell/comments/commentRss/189386.htmlhttp://www.aygfsteel.com/polygoncell/services/trackbacks/189386.html
在上一博客中Q我的enum是这么写的:

public enum Status implements DescriptionID {

    ACTIVATED(
5"This object is activated"),  
    DEACTIVATED(
9"This object is deactivated");

    
private Integer id;
    
private String description;
    
private static List<Status> list;

    
static {
        list 
= new ArrayList<Status>(2);
        list.add(ACTIVATED);
        list.add(DEACTIVATED);
    }

    
private Status(int statusNr, String description) {
        
this.id = statusNr;
        
this.description = description;
    }

    
public String getDescription() {

        
return this.description;
    }

    
public Integer getId() {
        
return id;
    }

    
public static List<Status> getAll() {
        
return list;
    }

    
public static Status findById(Integer id) {
        
for (Status status : getAll()) {
            
if (id == status.getId()) {
                
return status;
            }
        }
        
return null;
    }

}

其中两个staticҎ是ؓ了方便用?br />
~点一Q?br />
         所有的enum实例必须手动U_list集合中?br />
解决ҎQ?
 
        解决Ҏ非常单,是用ClasscL供的ҎgetEnumConstants()Q?代码如下Q?br />
    public static List<Status> getAll() {
        
return Arrays.asList(Status.class.getEnumConstants());
    }

我个人比较讨厌数l,因此q里Ҏ数l{换成List。如果你们不介意使用数组的话QgetAllQ)Ҏ完全可以省略?br />
~点二:

           findById(Integer id) Ҏ名ƈ不脓切,叫getEnumById(Integer id)会更好些。另外一模一LҎ必须在每一个enumcM重复~写Q如果某个地斚w要改动,那就需要改动所有相关的enumc,q是一个很明显的bad smell?br />
解决ҎQ?br />
        ~写一个utilc,逻辑转移到utilcMQgetEnumById(Integer id)Ҏ调用utilcM的相x法,代码如下Q?br />
    public static Status getEnumById(Integer id) {
        
return EnumUtils.getEnum(Status.class, id);
    }

public class EnumUtils {

    
public static <extends DescriptionID> I getEnum(Class<I> type, int id) {
        I[] types 
= type.getEnumConstants();
        
for (I t : types) {
            
if (t.getId() == id)
                
return t;
        }
        return null;

    }
}

q里getEnum(Class<I> type, int id)Ҏ利用Java 5的新Ҏgeneric,利用l定的Class和enum idQ返回对应的enum实例。这样处理好处很明显Q获取enum实例的逻辑代码只存在与utilcMQ日后修改十分方ѝ?br />
相关内容请参?span style="color: #000000;">我写?a target="_blank" title="《Hibernate 3和Java Persistence API E序开发从入门到精通? >《Hibernate 3和Java Persistence API E序开发从入门到精通?/a>一书?/span>


polygoncell 2008-03-29 00:58 发表评论
]]>
Hibernate user typehttp://www.aygfsteel.com/polygoncell/archive/2008/03/21/187788.htmlpolygoncellpolygoncellFri, 21 Mar 2008 12:14:00 GMThttp://www.aygfsteel.com/polygoncell/archive/2008/03/21/187788.htmlhttp://www.aygfsteel.com/polygoncell/comments/187788.htmlhttp://www.aygfsteel.com/polygoncell/archive/2008/03/21/187788.html#Feedback4http://www.aygfsteel.com/polygoncell/comments/commentRss/187788.htmlhttp://www.aygfsteel.com/polygoncell/services/trackbacks/187788.html《Hibernate 3和Java Persistence API E序开发从入门到精通?/a>Q书中着重介l了在Hibernate/JPA中用Annotation。最q有读者来信询问UserTypeQ再加上最q看到有的h在项目中滥用Hibernate的user typeQ想在这里说几句?br />
使用UserType首先要弄清楚它的目的。大家知道Hibernate解决的主要是对象数据库阻抗失衡的问题Q也是如何一个或多个对象保存C个或多个数据库表g。这其中有很多方法,其实大部分情况下采用@Embeddable?/tt>@Embedded可以解决问题了Q只有嵌入对象方式无法满求时Q或者是Hibernate默认的持久化方式无法满要求Ӟ才应该考虑UserType。MC一个原则,不到q水尽Q不要轻易用UserType。还有一个要慎重考虑使用UserType的原因是Q一旦采用了UserTypeQ你的项目就q了JPAQ而直接和Hibernate耦合在一起了?br />
扩展UserType主要分ؓ两种Q?br />
  1. immutable
  2. mutable
今天我先举个immutable的例子?br />
Java 5提出了一个新的enumc,JPA提供的标准方法是保存enum的name或者是ordinal。这U默认方式能够满x开发的目Q但是对于一些老项目翻新ƈ不一定适用。下面我们来看一个例子:

public class Status {

    
public static final int ACTIVATED = 5;
    
public static final int DEACTIVATED = 6;
}

q个是在java5之前常用的常量定义方法,老项目数据库里面已经保存了很多的5?的。现在要把Status改写成enumQ而且不希望修Ҏ据库中已有的数据Q怎么做?W一反应Qstatus enum可以q么写:

public enum Status {
        ACTIVATED,
        DEACTIVATED;
}

持久化enum的name属性是肯定不用考虑了,ordinal属性呢Q这里要保存的可??Q而Status enum只有两个实体Q他们的ordinal只是0?。而且目中还会有其他很多cM的常量类需要改写成enumQJPA的默认方式无法完成Q务,q时候可以开始考虑使用UserType了?br />
先定义一个接口,q样可以使用一个UserType支持所有类似的enumQ?br />
public interface DescriptionID {

    String getDescription();

    
int getId();
}

然后改写Status enum:

public enum Status implements DescriptionID {

    ACTIVATED(
5"This object is activated"),  
    DEACTIVATED(
9"This object is deactivated");

    
private Integer id;
    
private String description;
    
private static List<Status> list;

    
static {
        list 
= new ArrayList<Status>(2);
        list.add(ACTIVATED);
        list.add(DEACTIVATED);
    }

    
private Status(int statusNr, String description) {
        
this.id = statusNr;
        
this.description = description;
    }

    
public String getDescription() {

        
return this.description;
    }

    
public Integer getId() {
        
return id;
    }

    
public static List<Status> getAll() {
        
return list;
    }

    
public static Status findById(Integer id) {
        
for (Status status : getAll()) {
            
if (id == status.getId()) {
                
return status;
            }
        }
        
return null;
    }

}

注意q里每个enum都必L两个staticҎQ这些方法名必须在所有的enum中保持一致。ListQ)Ҏ是ؓ了方便获取所有的Status帔RQ例如在用户界面通过ComboBox展示QfindById()Ҏ是ؓ了通过l定Id获得对应的Enum实例。其中findById()Ҏ参数一定要是IntegerQ原因后面会讲到?br />
下面~写DescriptionIDUserTypeQ?br />


public class DescriptionIDUserType implements UserType, ParameterizedType {

    
private Class enumClass;

    
public void setParameterValues(Properties parameters) {
        
try {
            enumClass 
= ReflectHelper.classForName(parameters.getProperty("class"));
        } 
catch (ClassNotFoundException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
    
public Object assemble(Serializable cached, Object arg1)
            
throws HibernateException {

        
return cached;
    }
    
    
/*
     * (non-Javadoc)
     * 
     * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
     
*/
    
public Object deepCopy(Object value) throws HibernateException {
        
// TODO Auto-generated method stub
        return value;
    }

    
/*
     * (non-Javadoc)
     * 
     * @see org.hibernate.usertype.UserType#disassemble(java.lang.Object)
     
*/
    
public Serializable disassemble(Object value) throws HibernateException {
        
// TODO Auto-generated method stub
        return (Serializable) value;
    }

    
/*
     * (non-Javadoc)
     * 
     * @see org.hibernate.usertype.UserType#equals(java.lang.Object,
     *      java.lang.Object)
     
*/
    
public boolean equals(Object id1, Object id2) throws HibernateException {
        
if (id1 == id2) {
            
return true;
        }
        
if (id1 == null || id2 == null) {
            
return false;
        }

        
final DescriptionID did1 = (DescriptionID) id1;
        
final DescriptionID did2 = (DescriptionID) id2;

        
return did1.getId() == did2.getId()
                
&& StringUtils.equals(did1.getDescription(), did2
                        .getDescription());
    }

    
/*
     * (non-Javadoc)
     * 
     * @see org.hibernate.usertype.UserType#hashCode(java.lang.Object)
     
*/
    
public int hashCode(Object value) throws HibernateException {
        
// TODO Auto-generated method stub
        return value.hashCode();
    }

    
/*
     * (non-Javadoc)
     * 
     * @see org.hibernate.usertype.UserType#isMutable()
     
*/
    
public boolean isMutable() {
        
// TODO Auto-generated method stub
        return false;
    }

    
/*
     * (non-Javadoc)
     * 
     * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet,
     *      java.lang.String[], java.lang.Object)
     
*/
    
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner)
            
throws HibernateException, SQLException {
        
try {
            
int id = resultSet.getInt(names[0]);
            
if (resultSet.wasNull()) {
                
return null;
            }
            
return enumClass.getMethod("findById"new Class[] { Integer.class })
                    .invoke(
null, id);
        } 
catch (IllegalArgumentException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        } 
catch (SecurityException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        } 
catch (IllegalAccessException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        } 
catch (InvocationTargetException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        } 
catch (NoSuchMethodException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        }
        
return null;
    }

    
/*
     * (non-Javadoc)
     * 
     * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement,
     *      java.lang.Object, int)
     
*/
    
public void nullSafeSet(PreparedStatement statement, Object value, int index)
            
throws HibernateException, SQLException {
        
if (value == null) {
            statement.setNull(index, Hibernate.INTEGER.sqlType());
        } 
else {
            DescriptionID dID 
= (DescriptionID) value;
            statement.setInt(index, dID.getId());
        }
    }

    
/*
     * (non-Javadoc)
     * 
     * @see org.hibernate.usertype.UserType#replace(java.lang.Object,
     *      java.lang.Object, java.lang.Object)
     
*/
    
public Object replace(Object original, Object arg1, Object arg2)
            
throws HibernateException {
        
// TODO Auto-generated method stub
        return original;
    }

    
/*
     * (non-Javadoc)
     * 
     * @see org.hibernate.usertype.UserType#returnedClass()
     
*/
    
public Class returnedClass() {
        
return DescriptionID.class;
    }

    
/*
     * (non-Javadoc)
     * 
     * @see org.hibernate.usertype.UserType#sqlTypes()
     
*/
    
public int[] sqlTypes() {
        
return new int[]{Hibernate.INTEGER.sqlType()};
    }


}

我们的这个UserType是要支持实现DescriptionID的各U不同的enumQ而enum是没法承的。所以我们需要用L出具体的参数Q以q一步确定到底是哪个enumcR这也就D了,我们的这个类需要实?/span>ParameterizedType接口?/span>

׃enumcLw是immutable的,所以这个UserType的实现类相对比较单,主要的两个方法是
nullSafeGet?/span>nullSafeSet。在nullSaftGet中我们用Java Reflectionq借助用户l出的enumcd数直接调用该enumcȝfindByIdQ)ҎQ这h们就可以使用数据库中的integer扑ֈ对应的enum实例。注意,׃使用了Java Reflection,所以findById()Ҏ参数必须是Integer而非int?在nullSafeSet中,我们则通过DescriptionID接口直接获取enum实例的id属性,q且它保存到数据库中去?br />
最后看看怎么使用q个UserTypeQ?br />
@TypeDefs({@TypeDef(name = "status", typeClass = DescriptionIDUserType.class
                    parameters 
= {@Parameter(name = "class", value = "com.yourpackage.Status")})})
@Entity
public class SomeObject {

    
private Integer objectId;
    
private Status status;

    @Id
   
@GeneratedValue(strategy=GenerationType.AUTO)   
   
public Integer getObjectId() {
        
return objectId;
    }

    
public void setObjectId(Integer objectId) {
        
this.objectId = objectId;
    }

    @Type(type 
= "status")
    
public Status getStatus() {
        
return status;
    }

    
public void setStatus(Status status) {
        
this.status = status;
    }
}

其中值得讲讲的就是定义Type时用的parameter,"class"参数是我们自己定义的Q该参数?span style="color: #000000;">DescriptionIDUserType提供
了具体的enumcR前面已l讲q了Q?span style="color: #000000;">DescriptionIDUserType是在运行时态利用这个参数自定义enum与数据库之间的持久化逻辑?br />
使用q个UserType之后Q我们就可以在确保数据库数据不变的情况下Q成功地类型不保险的常量类改写成enumQ而且q个UserType支持所有实C
DescriptionID接口的enumcR?br />
cM的情冉|友们可以自由发挥了?br />
关于Annotation和Usertype的相关知识请参考我写的

polygoncell 2008-03-21 20:14 发表评论
]]>
վ֩ģ壺 | | ҵ| ׿| | | | | | ̨| | | ͨ| ¡| ຣʡ| | ɽ| | | Ρɽ| | Ϫ| | ɽ| | ˮ| | | пǰ| | ֹ| ׼| ɽ| ĩ| ƽ| ¹| ױ| ˳| | ̨| ֹ|