庄周梦蝶

生活、程序、未来
   :: 首页 ::  ::  :: 聚合  :: 管理

官方消息: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 阅读(2186) | 评论 (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 阅读(7526) | 评论 (0)编辑 收藏

    今日上午10时左右,在盖茨参加北大举行的“2007创新盛会”活动时,一位开源软件人士冲到台上抗议,并大呼“我们需要开源软件,需要自由!”。这个报道一开始听到的时候还是有点诧异,然后是释然,盖茨同学被人扔过鸡蛋了,更何况这么一句口号。而王开源做为一名公民,有权利去表达自己的观点。这样的抗议示威举动很正常,也应该被正常对待,社会各阶层的人士都有权利发出自己的声音。我可以不赞成你的观点,但我尊重你表达观点的权利。
    可后来看到很多的评论,对开源社区的谩骂,对王开源本人的人身攻击比比皆是,我不由地奇怪,微软在中国有这么多粉丝吗?也许答案是肯定的,在中国盗版猖獗,就像我亲爱的老婆以为电脑就是windows一样的人绝对不少。可作为业内的IT人的表现就有点说不过去了,我们不去抗议中国电信、国有银行垄断是因为我们不是那个行业的人,而作为软件业的一分子,人们有权利去抗议微软利用操作系统垄断带来的负面影响,人们有权利去表达支持开源事业,只要手段合法。

   国内的软件业处于国际软件生态链的最底端,在操作系统、编译器、程序设计语言、数据库等等核心技术全部掌握在国外大公司的手中,很多人以为软件设计就是C#,就是java,就是oracle、db2,而为了某个阵营可以对同为中国人的同胞骂的淋漓尽致,比如java VS C#, ruby VS java等等。这样的场景想想其实很搞笑。

   这件事情引申开来,其实从对待这件事情的态度上,也可以看到一个人接受的教育:是在威权主义影响下的犬儒人士,还是有自主思考能力的公民。也许王开源受到特殊对待的是那句“需要自由!”的口号吧,做到独立思考,从来不是件容易的事情。
  

posted @ 2007-04-21 13:06 dennis 阅读(591) | 评论 (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 阅读(3744) | 评论 (0)编辑 收藏

     摘要:     spring IOC容器的实现,一开始我被复杂的接口和类所掩埋,看不清整体的思路和设计,踟蹰于代码丛林中,摸不清前进的方向。一开始我就决定只研读以xml文件做配置文件的XmlFactoryBean的具体实现为主要目标,渐渐地有了点感觉,用UML把spring中的bean工厂体系展现出来之后就更清晰了,让你不得不感叹设计的精巧和复杂。本文只是我个人对spring...  阅读全文

posted @ 2007-04-20 11:59 dennis 阅读(15490) | 评论 (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 阅读(8451) | 评论 (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 阅读(4046) | 评论 (1)编辑 收藏

    好了,我终于买了《算法导论》和《计算机程序的构造与解释》,这半年不准备再追逐“时尚的技术”,潜心读这两本,相信自己一定能够做到。《Programming Ruby》这两天读完了,翻译的很好,尽管还是有很少的一些翻译和文字校验上的瑕疵,但比起某些翻译的跟天书似的已经好上很多,看的出来译者是很用心的。昨天读《Duck Typing》那章,动态语言的特色显示的淋漓尽致,不由拍案叫绝。而《类与对象》也深入阐述了ruby的OO模型,对于我准备读xruby的源码也有不小的帮助,当然,如果结合dreamhead的《管窥ruby系列》来读应该更有感触。
    钱真是个头痛的问题,工作一年半,银行里还是没存几个钱,残念,努力,努力。顺手给老婆买了只熊熊,哈哈,特价商品,可不能让她知道




posted @ 2007-04-15 11:02 dennis 阅读(863) | 评论 (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 阅读(2202) | 评论 (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 阅读(1659) | 评论 (0)编辑 收藏

仅列出标题
共56页: First 上一页 41 42 43 44 45 46 47 48 49 下一页 Last