莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理

          官方消息:http://labs.adobe.com/wiki/index.php/Flex:Open_Source

          Flex向微軟WPF開戰的新起點。正如預期的那樣,Adobe決定flex在Mozilla Public License (MPL)協議下納入開源社區,flex的前景很值的期待。

          posted @ 2007-04-26 17:02 dennis 閱讀(2216) | 評論 (7)編輯 收藏

              這兩天一直在讀spring1.2的AOP實現源碼,AOP實現原理說起來很簡單,對于實現業務接口的對象使用java代理機制實現,而對于一般的類使用cglib庫實現,但spring的實現還是比較復雜的,不過抓住了本質去看代碼就容易多了。發現一篇04年寫的《spring源碼分析:實現AOP》,倒是不用自己再寫了,04年的時候已經有很多人研讀過spring的源碼,而那時的我還在學校,對java半懂不懂的狀態,就算到現在也不敢說真的懂了,繼續學習、努力。文章如下:

             
          我的問題
                 為了完成公司應用開發平臺的設計,這幾天一直在研究Spring的擴展機制。Spring的核心無疑是BeanFactory, ApplicationContext和AOP。在“Spring AOP編程”教程的例子中,是由ProxyFactoryBean來實現的。問題來了,普通的bean和FactoryBean的配置完全是一樣的。那 么,BeanFactory是如何區分普通的Bean和用作Proxy的FactoryBean的?ProxyFactoryBean又是怎樣實現AOP 功能的?(本文還很不完善,我會繼續修改。)
           
          FactoryBean的職責
                  FactoryBean在Spring中被當成一種特殊的bean,通過實現FactoryBean接口進行擴展。FactoryBean的職責是:
                  l.封裝了創建對象或查找對象的邏輯。
                 2.提供了一個中間層,用于支持AOP。

                 我們來看一個LocalStatelessSessionProxyFactoryBean的例子。首先,定義Stateless EJB的代理,id為ejbServiceProxy:
                 <bean id="ejbServiceProxy" class="LocalStatelessSessionProxyFactoryBean">
                     <property name="jndiName">     
                        <value>myEjb</value>
                     </property>
                     <property name="businessInterface">
                        <value>com.mycompany.MyBusinessInterface</value>
                     </property>
                </bean>
           
                然后,再將這個業務邏輯服務對象注入客戶程序:
               <bean id="myAction" class = "samples.myAction">
                   <property name="myService">
                       <ref bean="ejbServiceProxy"/>
                   </property>
               </bean>

               這樣,客戶程序并不知道myService的實現細節,Spring使用FactoryBean完成了兩者之間的解耦。
           
          準備代碼分析環境
               1. 安裝Eclipse和Spring IDE。
               2. 下載Spring framework源代碼,并導入Eclipse。
               3. 在類路徑創建log4j.properties配置文件,設置如下:
                       log4j.rootLogger=DEBUG, stdout
                       log4j.appender.stdout=org.apache.log4j.ConsoleAppender
                       log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
                       log4j.appender.stdout.layout.ConversionPattern=%d{SSS} %p %c{2} - %m%n
               4. 編寫TestCase,跟蹤Console窗口的debug信息。

          FactoryBean源代碼分析
                 如果bean實現了FactoryBean接口,BeanFactory將把它作為一個bean工廠,而不是直接作為普通的bean。正常情況下, BeanFactory的getBean("bean")返回FactoryBean生產的bean實例,如果要返回FactoryBean本身的實例, 使用getBean("&bean")的調用方式。
                 在分析ProxyFactoryBean之前,我們先分析BeanFactory,它是Spring Framework的基礎。我們看看它是如何分別處理普通的Bean和FactoryBean的。
           
            BeanFactory分析
           
               BeanFactory類圖
           
                 如以上的類圖所示,XmlBeanFactory繼承了AbstactBeanFactory抽象類。AbstactBeanFactory類中使用了 Template Method設計模式,其中的模板方法為getBeanDefinition()和createBean()兩個抽象方法。其中 AbstractAutowireCapableBeanFactory類實現了getBeanDefinition()方法, DefaultAutowireCapableBeanFactory類實現了getBeanDefinition()方法。當調用getBean()方 法時,AbstractBeanFactory類定義的邏輯分別調用了這兩個模板方法。

               BeanFactory類的調用順序
                 我們暫時不使用ApplicationContext,以簡化分析過程。我在這里使用了“Spring AOP編程”的例子,請參照該教程閱讀。首先,編寫測試用例,代碼如下:

                      public class AopTest extends TestCase {
                            XmlBeanFactory factory = null;
                            protected void setUp() throws Exception {
                                 super.setUp();
                                 InputStream is = new FileInputStream("testaop.xml");
                                 factory = new XmlBeanFactory(is);
                            }
                            public void testGetBean() {
                                 Bean bean = (Bean)factory.getBean("bean");
                                 assertNotNull(bean);
                                 bean.theMethod();
                            }
                      }
           
                 1. 首先,XmlBeanFactory使用XmlBeanDefinitionReader讀入testaop.xml配置文件,后者用 XmlBeanDefinitionParser和DefaultXmlBeanDefinitionParser進行分析,從中得到 BeanDefinition的信息,并保存在XmlBeanDefinitionReader的BeanDefinitionRegistry變量里。
                 2. 客戶程序調用getBean方法時,AbstractBeanFactory首先使用transFormedBeanName方法分析傳入的Bean名稱,判斷客戶程序需要FactoryBean本身,還是它所創建的Bean對象。
                 3. 接下來,如果bean被定義為singleton模式,AbstractBeanFactory調用createBean方法根據 BeanDefinition信息實例化bean類,然后將該bean實例傳給getObjectForSharedInstance方法并返回 getObjectForSharedInstance的返回對象。GetObjectForSharedInstance方法摘要如類圖所示,首先判斷 bean是否繼承了FactoryBean。如果是,返回FactoryBean的getObject方法(下節我將詳細分析使用 ProxyFactoryBean如何實現AOP);如果不是,返回bean對象。
                 4. 如果bean被定義為prototype模式,每次客戶程序請求都會生成新的bean實例,因此,createBean方法直接實例化bean對象并返回。
           
            ProxyFactoryBean如何實現AOP

               ProxyFactoryBean類圖
                 FactoryBean接口如下圖所示,共有三個方法getObject,getObjectType,和isSingleton。ProxyFactoryBean實現了FactoryBean接口,它的相關類圖如下:
           

           
               實現AOP的過程
                 如上圖所示,ProxyFactoryBean類繼承了AdvisedSupport類,后者繼承了ProxyConfig類并定義了操作advisor 和interceptor的接口,以支持AOP。當BeanFactory實例化ProxyFactoryBean時,根據配置文件的定義將關于 advice,pointcut,advisor,所代理的接口和接口實現類的所有信息傳給ProxyFactoryBean。
                 當客戶程序調用BeanFactory的getBean方法時,ProxyFactory使用JdkDynamicAopProxy實例化 BeanImpl類,并用JdkDynamicAopProxy的invoke方法執行advice。至于執行advice的時機,由 ProxyFactoryBean調用RegexpMethodPointcutAdvisor進行判斷。


          posted @ 2007-04-24 09:37 dennis 閱讀(7545) | 評論 (0)編輯 收藏

              今日上午10時左右,在蓋茨參加北大舉行的“2007創新盛會”活動時,一位開源軟件人士沖到臺上抗議,并大呼“我們需要開源軟件,需要自由!”。這個報道一開始聽到的時候還是有點詫異,然后是釋然,蓋茨同學被人扔過雞蛋了,更何況這么一句口號。而王開源做為一名公民,有權利去表達自己的觀點。這樣的抗議示威舉動很正常,也應該被正常對待,社會各階層的人士都有權利發出自己的聲音。我可以不贊成你的觀點,但我尊重你表達觀點的權利。
              可后來看到很多的評論,對開源社區的謾罵,對王開源本人的人身攻擊比比皆是,我不由地奇怪,微軟在中國有這么多粉絲嗎?也許答案是肯定的,在中國盜版猖獗,就像我親愛的老婆以為電腦就是windows一樣的人絕對不少。可作為業內的IT人的表現就有點說不過去了,我們不去抗議中國電信、國有銀行壟斷是因為我們不是那個行業的人,而作為軟件業的一分子,人們有權利去抗議微軟利用操作系統壟斷帶來的負面影響,人們有權利去表達支持開源事業,只要手段合法。

             國內的軟件業處于國際軟件生態鏈的最底端,在操作系統、編譯器、程序設計語言、數據庫等等核心技術全部掌握在國外大公司的手中,很多人以為軟件設計就是C#,就是java,就是oracle、db2,而為了某個陣營可以對同為中國人的同胞罵的淋漓盡致,比如java VS C#, ruby VS java等等。這樣的場景想想其實很搞笑。

             這件事情引申開來,其實從對待這件事情的態度上,也可以看到一個人接受的教育:是在威權主義影響下的犬儒人士,還是有自主思考能力的公民。也許王開源受到特殊對待的是那句“需要自由!”的口號吧,做到獨立思考,從來不是件容易的事情。
            

          posted @ 2007-04-21 13:06 dennis 閱讀(607) | 評論 (2)編輯 收藏

          最近項目的websphere經常當機,運行一段時間后變慢然后當掉。查找了下網上的資料,盡管不是我在負責服務器,但是也是個學習的機會。

          主要針對的癥狀:  
                  平臺:was5.1   base,http   server   1.3.28,oracle   8i,9i  
                  癥狀:用戶響應突然變慢,然后并連接不上80端口,重啟后正常,一段時間后反復  
                  解決方式:調整服務器參數,增加服務器的處理能力  
             
                  1,更改http   server的配置文件參數KeepAlive。  
                原因:這個值說明是否保持客戶與HTTP   SERVER的連接,如果設置為ON,則請求數到達MaxKeepAliveRequests設定值時請求將排隊,導致響應變慢。  
                方法:打開ibm   http   server安裝目錄,打開文件夾conf,打開文件httpd.conf,查找KeepAlive值,改ON為OFF,其默認為ON  
             
            2,更改http   server的配置文件參數ThreadsPerChild值到更大數目,默認為50  
                原因:服務器響應線程的數量  
                方法:打開ibm   http   server安裝目錄,打開文件夾conf,打開文件httpd.conf,查找ThreadsPerChild值,默認為50,改到更大數目,視用戶數 多少而定,一般改到客戶機數量的1.1倍,如200臺,則設為220  
             
            3,關閉http   server日志紀錄  
                    原因:http   server的日志IO影響性能  
                    方法:打開ibm   http   server安裝目錄,打開文件夾conf,打開文件httpd.conf,查找CustomLog值,找到沒有注釋的那行(行的開頭沒有符號"#"), 將那行用符號"#"注釋掉,以關閉日志紀錄,提高處理性能。  
             
            4,更改Websphere的服務器處理線程數  
                    原因:線程的數量影響同時并發的請求數量  
                    方法:打開管理控制臺,依次打開目錄樹,服務器->server1->web容器->線程池,修改"最大大小"的值,默認是50,改到 更大數目,具體視總用戶數量和機器的配置而定,一般設置其等于或小于http   server設置的MaxKeepAliveRequests的值。

              根據上面的建議,查看了下我們的服務器配置情況,倒是沒什么不同,實際上導致服務相應變慢到停止,一般是由兩個原因導致的  
            1,數據庫操作時間過長(如查詢),導致占用連結時間過長,然后后續請求無法及時取得連結響應請求  
            2,代碼中一定要確保連結關閉,尤其在jsp中。后臺程序要在finally中關閉
              由此,我查看了System.out的日志,發現每次在當機前都有報“連接郵件服務器失敗”類似的錯誤,我們的郵件服務器是ibm的Lotus Domino,最近的網絡狀況很有問題,個人懷疑是因為連接郵件服務器時間過長,導致了這種情況的發生,有待證實。   

          posted @ 2007-04-20 13:06 dennis 閱讀(3789) | 評論 (0)編輯 收藏

               摘要:     spring IOC容器的實現,一開始我被復雜的接口和類所掩埋,看不清整體的思路和設計,踟躕于代碼叢林中,摸不清前進的方向。一開始我就決定只研讀以xml文件做配置文件的XmlFactoryBean的具體實現為主要目標,漸漸地有了點感覺,用UML把spring中的bean工廠體系展現出來之后就更清晰了,讓你不得不感嘆設計的精巧和復雜。本文只是我個人對spring...  閱讀全文

          posted @ 2007-04-20 11:59 dennis 閱讀(15541) | 評論 (12)編輯 收藏

               摘要:     一直使用prototype.js,因為prototype的風格與ruby相似,用起來很舒服;這兩天抽空看看jQuery,也是個很優秀的js基礎庫,特別是在選擇器方面,相當實用。轉自:http://www.cnblogs.com/skylaugh/archive/2006/12/18/595563.html 翻譯整理:Young.J官方網站:http://jq...  閱讀全文

          posted @ 2007-04-19 13:51 dennis 閱讀(8481) | 評論 (2)編輯 收藏

              這個包的說明是說主要是包括用于操作JavaBean的類和接口,將被大部分spring包使用。在讀這個包的代碼前,我特意將JavaBean規范讀了一遍。JavaBean規范不僅僅是getter、setter,定義了一個完整的輕量級組件模型,事件、方法、屬性、持久化等等支持均包含在內。JavaBean規范很明顯是學習Delphi的組件模型,sun希望通過它來形成一個java組件的市場,可惜結果不如人意,JavaBean在GUI方面并未形成一個類似delphi控件市場;隨著spring等輕量級框架的流行,而EJB重量級的組件模型被越來越多的人放棄,JavaBean反而在服務端模型方面占據了主流 。廢話不提,這個包的核心接口和類就是BeanWrapper和BeanWrapperImpl,顧名思義,這個接口就是用于包裝JavaBean的行為,諸如設置和獲取屬性,設置屬性編輯器等(PropertyEditor)。看下這個包的核心類圖:

          BeanWrapper接口繼承了PropertyAccessor(用于屬性訪問和設置)和PropertyEditorRegistry(屬性編輯器的獲取和設置),而BeanWrapperImpl除了實現BeanWrapper接口外還繼承自PropertyEditorRegistrySupport 類。在PropertyEditorRegistrySupport 類中可以看到spring默認設置的一系列自定義PropertyEditor。比如:
          protected void registerDefaultEditors() {
                  
          this.defaultEditors = new HashMap(32);

                  
          // Simple editors, without parameterization capabilities.
                  
          // The JDK does not contain a default editor for any of these target types.
                  this.defaultEditors.put(Class.classnew ClassEditor());
                  
          this.defaultEditors.put(File.classnew FileEditor());
                  
          this.defaultEditors.put(InputStream.classnew InputStreamEditor());
                  
          this.defaultEditors.put(Locale.classnew LocaleEditor());
                  
          this.defaultEditors.put(Properties.classnew PropertiesEditor());
                  
          this.defaultEditors.put(Resource[].classnew ResourceArrayPropertyEditor());
                  
          this.defaultEditors.put(String[].classnew StringArrayPropertyEditor());
                  
          this.defaultEditors.put(URL.classnew URLEditor());

          。。。。。。。

              PropertyEditor的概念就是屬性編輯器,或者說屬性轉換器,比如我們在spring的配置文件中設置某個bean的class,這是一個字符串,怎么轉換為一個Class對象呢?通過上面注冊的ClassEditor,看看這個類是怎么實現的:

          public class ClassEditor extends PropertyEditorSupport {

              
          private final ClassLoader classLoader;

              /**
               * Create a default ClassEditor, using the given ClassLoader.
               * 
          @param classLoader the ClassLoader to use
               * (or <code>null</code> for the thread context ClassLoader)
               
          */
              
          public ClassEditor(ClassLoader classLoader) {
                  
          this.classLoader =
                          (classLoader 
          != null ? classLoader : Thread.currentThread().getContextClassLoader());
              }


              
          public void setAsText(String text) throws IllegalArgumentException {
                  
          if (StringUtils.hasText(text)) {
                      
          try {
                          //調用輔助類,得到Class對象
                          setValue(ClassUtils.forName(text.trim(), 
          this.classLoader));
                      }
                      
          catch (ClassNotFoundException ex) {
                          
          throw new IllegalArgumentException("Class not found: " + ex.getMessage());
                      }
                  }
                  
          else {
                      setValue(
          null);
                  }
              }

              
          public String getAsText() {
                  Class clazz 
          = (Class) getValue();
                  
          if (clazz == null) {
                      
          return "";
                  }
                  
          if (clazz.isArray()) {
                      
          return clazz.getComponentType().getName() + ClassUtils.ARRAY_SUFFIX;
                  }
                  
          else {
                      
          return clazz.getName();
                  }
              }

          }
              代碼已經解釋了一切,繼承javabean的PropertyEditorSupport,自己實現轉換即可。這個包另外就是定義了一個完整的異常體系,值的我們參考。另外一個值的注意的地方是CachedIntrospectionResults類的實現,這個類使用了單例模式,它的作用在于緩存JavaBean反省(Introspect)得到的信息,因為每次使用Introspector對獲取JavaBean信息是個不小的性能開支。緩存使用的是WeakHashMap,而不是HashMap,看看spring的解釋:
          /**
               * Map keyed by class containing CachedIntrospectionResults.
               * Needs to be a WeakHashMap with WeakReferences as values to allow
               * for proper garbage collection in case of multiple class loaders.
               
          */
              
          private static final Map classCache = Collections.synchronizedMap(new WeakHashMap());

          因為緩存使用的key是bean的Class對象(以保證唯一性),因此在應用存在多個class loaders的時候,為了保證垃圾收集的進行,不出現內存泄露而采用WeakHashMap,為了理解這一點,我用JProfiler測試了自定義ClassLoader情況下,內存堆的使用情況,從快照上看。在使用HashMap的情況下,因為測試的bean的Class對象被載入它的ClassLoader以及java.beans.BeanInfo,java.beans.PropertyDescriptor,java.lang.reflect.Method這四個對象強引用,而導致不可回收。而在使用WeakHashMap時,判斷當載入bean的ClassLoader和載入CachedIntrospectionResults的ClassLoader是不同的時候,使用弱引用包裝緩存對象,當垃圾收集起發現弱引用時將馬上清除弱引用對象,該弱引用也將加入一個隊列,而WeakHashMap將定時檢查這個隊列,當有新的弱引用達到時(意味著已經被回收)就清除相應的鍵值。請看:
          private static boolean isCacheSafe(Class clazz) {
                  
          //CachedIntrospectionResults的ClassLoader
                  ClassLoader cur = CachedIntrospectionResults.class.getClassLoader();
                  
          //載入bean的ClassLoader
                  ClassLoader target = clazz.getClassLoader();
                  
          if (target == null || cur == target) {
                      
          return true;
                  }
                  
          while (cur != null) {
                      cur 
          = cur.getParent();
                      
          if (cur == target) {
                          
          return true;
                      }
                  }
                  
          return false;
              }

          public static CachedIntrospectionResults forClass(Class beanClass) throws BeansException {

             
             
          boolean cacheSafe = isCacheSafe(beanClass);
             
          if (cacheSafe) {
                          classCache.put(beanClass, results);
                      }
                      
          else {
                     //弱引用   
                      classCache.put(beanClass, new WeakReference(results));

                      }
             

              不知道我的理解是否有誤,如果有誤,請不吝指出,謝謝。

          posted @ 2007-04-16 10:23 dennis 閱讀(4087) | 評論 (1)編輯 收藏

              好了,我終于買了《算法導論》和《計算機程序的構造與解釋》,這半年不準備再追逐“時尚的技術”,潛心讀這兩本,相信自己一定能夠做到?!禤rogramming Ruby》這兩天讀完了,翻譯的很好,盡管還是有很少的一些翻譯和文字校驗上的瑕疵,但比起某些翻譯的跟天書似的已經好上很多,看的出來譯者是很用心的。昨天讀《Duck Typing》那章,動態語言的特色顯示的淋漓盡致,不由拍案叫絕。而《類與對象》也深入闡述了ruby的OO模型,對于我準備讀xruby的源碼也有不小的幫助,當然,如果結合dreamhead的《管窺ruby系列》來讀應該更有感觸。
              錢真是個頭痛的問題,工作一年半,銀行里還是沒存幾個錢,殘念,努力,努力。順手給老婆買了只熊熊,哈哈,特價商品,可不能讓她知道




          posted @ 2007-04-15 11:02 dennis 閱讀(903) | 評論 (0)編輯 收藏

              RubyGems是一個庫和程序的標準化打包以及安裝框架,它使定位、安裝、升級和卸載Ruby包變的很容易。rails以及它的大部分插件都是以gem形式發布的。本文描述一個自己創建ruby Gems的過程。
              假設你今天用ruby實現了一個stack結構,你想發布到網上讓別人可以共享,OK,工作開始了。首先你的程序當然要先寫好了:
          #stacklike.rb
          module Stacklike
           attr_reader:stack
           
          def initialize
              @stack
          =Array.new
           end
           
          def add_to_stack(obj)
              @stack.push(obj)
           end 
           
          def take_from_stack
              @stack.pop
           end
           
          def size
              @stack.length
           end
           alias length size
           
           
          def clear
             @stack.clear
           end
          end      

          然后就是我們的Stack類,引入這個Module,請注意,我們這里只是特意這樣做,增加點復雜度:
          #stack.rb
          require 
          'stacklike'
          class Stack
           include Stacklike
          end

           

          作為一個要被大眾使用的小程序,一定要有完備的測試代碼,OK,ruby內置了單元測試庫,我們來寫個單元測試來測試Stack:
          require 'stack'
          require 
          'test/unit'
          class TestStack <Test::Unit::TestCase
            
          def testStack
              stack
          =Stack.new
              assert_equal(0,stack.size)
              assert_equal(stack.length,stack.size) 
              stack.add_to_stack(
          1)
              assert_equal(
          1,stack.length)
              assert_equal(
          1,stack.take_from_stack)
              
              stack.clear
              assert_equal(0,stack.length)
              assert_nil(stack.take_from_stack)
              
              
          10.times{|i| stack.add_to_stack(i)}
              assert_equal(
          10,stack.size)
              assert_equal(stack.length,stack.size)
              
          9.downto(4){|i| assert_equal(i,stack.take_from_stack)} 
              
              assert_equal(
          4,stack.length)
              assert_equal(
          3,stack.take_from_stack)
              assert_equal(
          3,stack.length)
              
              stack.clear
              assert_equal(0,stack.length)
              assert_nil(stack.take_from_stack)
            end
          end

          如果你使用radrails或者RDT運行這段代碼,你將看到讓人舒服的greenbar,一切正常。程序寫好了,接下來就是關鍵步驟了,怎么發布成ruby Gems呢?

          第一步,寫Gems規范文件
             gemspec是ruby或者YAML形式的元數據集,用來提供這個gem的關鍵信息,我們創建一個文件夾就叫stack,然后在下面建立2個目錄兩個文件:
          lib目錄:用于存放庫的源代碼,比如這個例子中的stack.rb,stacklike.rb
          test目錄:用于存放單元測試代碼。
          README文件:描述你的庫的基本信息和版權許可證等
          stack.gemspec:gems規范文件,用以生成gem
          當然,也可以有docs目錄用以存放rdoc文檔和ext目錄用以存放ruby擴展,我們這個簡單例子就免了。
          看看我們的規范文件:
          #stack.spec
          require 
          'rubygems'
          SPEC
          =Gem::Specification.new do |s|
            s.name
          ="Stack"
            s.version
          ='0.01'
            s.author
          ='dennis zane'
            s.email
          ="killme2008@gmail.com"
            s.homepage
          ="http://www.rubyeye.net"
            s.platform
          =Gem::Platform::RUBY
            s.summary
          ="ruby實現的Stack"
            condidates 
          =Dir.glob("{bin,lib,docs,test}/**/*")
            s.files
          =condidates.delete_if do |item|
              item.include?(
          "CVS")|| item.include?("rdoc")
            end
            s.require_path
          ="lib"
            s.autorequire
          ='stack,stacklike'
            s.test_file
          ="test/ts_stack.rb"
            s.has_rdoc
          =false
            s.extra_rdoc_files
          =["README"]
          end  

          很明顯,規范文件也是ruby程序(也可以用YAML描述),設置了這個gem的主要關鍵信息:名稱、作者信息、平臺,需要注意的就是files數組過濾掉了cvs和rdoc文件,require_path和auto_require讓你指定了require_gem裝入gem時會被添加到$LOAS_PATH(ruby查找庫的路徑)中的目錄(也就是我們源代碼存放的lib),auto_require指定了裝載的文件名,我們沒有rdoc,所有設置has_rdoc為false,附帶文檔就是README。

          第二步 修改單元測試文件引用路徑
          過去我們假設ts_stack.rb與stack.rb、stacklike.rb在同一個目錄下,可是我們現在將它們分別放在lib和test目錄,TestStack 怎么引用測試的類呢?答案是在ts_stack.rb開頭加上一行:
          $:.unshift File.join(File.dirname(__FILE__),"..","lib")

          最后一步 構建gem
          在stack目錄執行下列命令:
          ruby stack.gemspec
           
          或者:
          gem build stack.gemspec
          將生成一個文件,你可以將這個文件共享給朋友們咯。你的朋友只要下載這個文件,執行:
          gem install Stack.0.01.gem
          將在他們的ruby環境中安裝你寫的stack,比較遺憾的是,你這個stack確實太簡陋了,哈哈。



          posted @ 2007-04-12 20:38 dennis 閱讀(2221) | 評論 (0)編輯 收藏

              這個包按照說明是:Interfaces and classes for type-safe enum support on JDK >= 1.3。提供類型安全的枚舉類型。代碼也是相當簡單,枚舉類型又分為靜態類型和通用類型。靜態類型其實跟jdk1.5引進的enum類型類似,都是以int類型做code,比如聲明一個Dog類型:
          public static class Dog extends StaticLabeledEnum {

                 
          private Dog(int code, String name) {
                      
          super(code, name);
                  }
              }

          然后就可以這樣聲明枚舉類型了:

          public static final Dog BORDER_COLLIE = new Dog(13"Border Collie");

          public static final Dog WHIPPET = new Dog(14"Whippet");

          public static final Dog GOLDEN_RETRIEVER = new Dog(11null) {
                      
          // must set type to be recognized as a "Dog"
                      public Class getType() {
                          
          return Dog.class;
                      }

                      
          public String getLabel() {
                          
          return "Golden Retriever";
                      }
                  };

          同時有一個靜態枚舉類型的處理類用于提取信息:StaticLabeledEnumResolver ——這個類繼承自抽象類AbstractCachingLabeledEnumResolver,而抽象類實現了接口LabeledEnumResovler,看看這個接口就知道所謂處理類是干什么的了:
          public interface LabeledEnumResolver {

              
          //獲取某個類中聲明的枚舉類型,這些類型   //必須是LabeledEnum的子類
              public Set getLabeledEnumSet(Class type) throws IllegalArgumentException;

              
          public Map getLabeledEnumMap(Class type) throws IllegalArgumentException;
             
              //根據code獲取枚舉
              
          public LabeledEnum getLabeledEnumByCode(Class type, Comparable code) throws IllegalArgumentException;

              //根據lable獲取枚舉
              
          public LabeledEnum getLabeledEnumByLabel(Class type, String label) throws IllegalArgumentException;

          }

          StaticLabeledEnumResolver 使用了單例模式,同時AbstractCachingLabeledEnumResolver定義了一個模板法方法并使用:
          protected abstract Set findLabeledEnums(Class type);
          也是一個Template Method模式應用的例子。

          所謂通用性的枚舉類型,是指不定義成static,并且可以靈活使用其他類型做code的枚舉,比如spring已經內置的3種:ShortCodedLabeledEnum ,StringCodeLabeledEnum和LetterCodeLabeledEnum,這些類都繼承自AbstractLabeledEnum,類名已經顯示了它們的用途,不再細說。這個包完整的類圖如下:
           

          posted @ 2007-04-11 15:57 dennis 閱讀(1699) | 評論 (0)編輯 收藏

          僅列出標題
          共56頁: First 上一頁 41 42 43 44 45 46 47 48 49 下一頁 Last 
          主站蜘蛛池模板: 于田县| 枣阳市| 嘉定区| 紫阳县| 昌黎县| 呼图壁县| 洱源县| 蚌埠市| 江孜县| 安岳县| 临城县| 鄱阳县| 万山特区| 天镇县| 长岛县| 通山县| 尼勒克县| 道真| 夏邑县| 望谟县| 康保县| 五台县| 清丰县| 义马市| 淮阳县| 古田县| 舒城县| 庆安县| 满城县| 高要市| 恩平市| 芮城县| 来宾市| 宝山区| 屏山县| 澎湖县| 冷水江市| 天水市| 安福县| 沅江市| 潞西市|