<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>我想网 &#187; Java</title>
	<atom:link href="http://www.iwanna.cn/topics/develope/java/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.iwanna.cn</link>
	<description></description>
	<lastBuildDate>Mon, 26 Dec 2011 05:46:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>根据url提取网站域名的方法小结</title>
		<link>http://www.iwanna.cn/archives/2010/10/17/5561/</link>
		<comments>http://www.iwanna.cn/archives/2010/10/17/5561/#comments</comments>
		<pubDate>Sun, 17 Oct 2010 12:32:03 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[程序源码]]></category>
		<category><![CDATA[Source-code]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5561</guid>
		<description><![CDATA[前言：最近使用到了他人总结的一个基础类库。查看了下源码，发现String帮助类的一个辅助方法不是很严谨，重构之。 1、原来程序的写法 public static string GetDomainName(string url) { Regex reg = new Regex(@"http(s)?://([\w-]+\.)+[\w-]+/?"); string result = reg.Match(url, 0).Value; if (result.IndexOf("http://") &#62; -1) { result = result.Replace("http://", string.Empty); } else if (result.IndexOf("https://") &#62; -1) { result = result.Replace("https://", string.Empty); } return result.Replace("/", string.Empty); } 2、改进方案 上面的写法，我认为不严谨的地方有两处：a、没有区分部分字符串的大小写（虽然通常传入的url都是小写http(s)开头的，使用起来问题不 大）；b、参数没有考虑为null的情况。下面给出我的几种解决方法，个人认为相对而言比较简洁严谨一些。 （1）正则改进 按照原来代码的写法，正则表达式是先提取出形如 http://www.iwanna.cn/ 的形式的字符串，然后再处理字符串。字符串替换和hard coding看起来会比较多，而且，毫无疑问，上面代码中的正则提取的字符串稍显冗余。我的改进如下： public static string GetDomainName(string [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>前言：最近使用到了他人总结的一个基础类库。查看了下源码，发现String帮助类的一个辅助方法不是很严谨，重构之。</p></blockquote>
<p>1、原来程序的写法</p>
<pre>      public static string GetDomainName(string url)
        {
            <a href="http://www.iwanna.cn/tags/regex/" class="st_tag internal_tag" rel="tag" title="标签 RegEx 下的日志">Regex</a> reg = new <a href="http://www.iwanna.cn/tags/regex/" class="st_tag internal_tag" rel="tag" title="标签 RegEx 下的日志">Regex</a>(@"http(s)?://([\w-]+\.)+[\w-]+/?");
            string result = reg.Match(url, 0).Value;
            if (result.IndexOf("http://") &gt; -1)
            {
                result = result.Replace("http://", string.Empty);
            }
            else if (result.IndexOf("https://") &gt; -1)
            {
                result = result.Replace("https://", string.Empty);
            }
            return result.Replace("/", string.Empty);
        }</pre>
<p><span id="more-5561"></span><br />
2、改进方案</p>
<p>上面的写法，我认为不严谨的地方有两处：a、没有区分部分字符串的大小写（虽然通常传入的url都是小写http(s)开头的，使用起来问题不 大）；b、参数没有考虑为null的情况。下面给出我的几种解决方法，个人认为相对而言比较简洁严谨一些。</p>
<p>（1）<strong>正则改进</strong></p>
<p>按照原来代码的写法，正则表达式是先提取出形如 <a href="http://www.iwanna.cn/" target="_blank">http://www.iwanna.cn/</a> 的形式的字符串，然后再处理字符串。字符串替换和hard  coding看起来会比较多，而且，毫无疑问，上面代码中的正则提取的字符串稍显冗余。我的改进如下：</p>
<pre>   public static string GetDomainName(string url)
        {
            if (url == null)
            {
                throw new Exception("输入的url为空");
            }
            Regex reg = new Regex(@"(?&lt;=[://])([\w-]+\.)+[\w-]+/?", RegexOptions.IgnoreCase);
            return reg.Match(url, 0).Value.Replace("/", string.Empty);
        }
</pre>
<p>应该说这是比较忠实于源代码的一种实现。<br />
【UPDATE】：根据文章后面布袋和尚<a href="http://www.cnblogs.com/mobydick/" target="_blank">说不得</a>大师的指点，再改进一下正则表达式，这样对于正常的 url路径或其他类型的路径都可以进行验证匹配了。代码如下：</p>
<pre>   public static string GetDomainName(string url)
        {
            if (url == null)
            {
                throw new Exception("输入的url为空");
            }
            Regex reg = new Regex(@"(?&lt;=://)([\w-]+\.)+[\w-]+(?&lt;=/?)");
            return reg.Match(url, 0).Value.Replace("/", string.Empty);
        }
</pre>
<p>（2）<strong>直接拼接字符串 </strong></p>
<p>拼接字符串在实际开发中可以做很多事情，简单的域名提取自然不在话下。我们分析一下输入的url，发现很显著也很重要的一个特征就是通过斜线 （/）来分割字符串，每一个分隔后的字符串分别表示不同的属性，如对应的协议名称，域名，站点名，页面名称等等。具体分割拼接提取的方法如下：</p>
<pre>     public static string GetDomainName(string url)
        {
             if (url == null)
            {
                throw new Exception("输入的url为空");
            }
            string result = string.Empty;
            string[] strArr = url.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string item in strArr)
            {
                if (string.Compare("http:", item.ToLower()) == 0)
                {
                    continue;
                }
                else if (string.Compare("https:", item.ToLower()) == 0)
                {
                    continue;
                }
                result = item;
                break;
            }
            return result;
        }
</pre>
<p>严格来说，这个是比较“笨”的方法，但是通俗易懂。</p>
<p>（3）<strong>通过一个HttpRequest对象获取它的Url的Host</strong></p>
<p>平时我们都是通过HttpRequest对象获取它的Url的Host来获取网站域名，现在只有一个字符串参数url，很显然，我们会 想到构造一个HttpRequest对象，然后按步就班即可。具体方法如下：</p>
<pre>        public static string GetDomainName(string url)
        {
            string result = null;
            try
            {
                HttpRequest request = new HttpRequest(string.Empty, url, string.Empty);
                result = request.Url.Host;
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("当前输入的URL:{0},发生异常：{1}", url, ex.Message));
            }
            return result;
        }</pre>
<p>这个应该算是另辟蹊径的一种解决方案，可是必需要引用System.Web dll，作为基础类库，应该越少引用越好。</p>
<blockquote><p>结语：到这里，根据url提取host的常规方法基本重构完成，没有过分考虑效率和性能，不知哪种会更快一点。期待您更好的方法和意见。</p></blockquote>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/10/17/5561/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/10/17/5561/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/10/17/5561/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/10/17/5561/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/10/17/5561/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/10/17/5561/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>选择哪个MongoDB插件？</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5285/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5285/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 16:42:58 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5285</guid>
		<description><![CDATA[相信MongoDB的名头不少人 已经听说过了，虽然已有针对它的Java驱动，但我敢打保票，只要你用过一次，很快就会怀念使用GORM的好时光。拜Grails的插件架构所赐，对于Grails项目来说，这不再是幻想。目前在Grails社区至少已经有两个针对MongoDB的插件：MongoDB Tools和Grails MongoDB plugin，我们该选择哪一个呢？ 在查看了两个插件的信息后，我坚定地选择了后者：Grails MongoDB plugin。 原因无它：完全保留了GORM的使用习惯，而且特性几乎一样： 实例方法：save、delete 类方法：get、find、findAll、delete、deleteAll、exists、count、list 诸如findAllByNameAndDegreeBetween(&#8230;)这样的动态查找器 支持约束和验证 支持自动时辍：dateCreated和lastUpdated Gorm事件：beforeSave、afterSave、beforeDelete、afterDelete（还有Morphia支持的 afterLoad） 支持MongoDB 1.4和1.5 提供了注入所有必需字段和Morphia注解的AST Transformations 支持延迟引用 支持generate-all 注意最后一个点，这个插件甚至支持了脚手架代码的产生！反观MongoDB Tools，看完它的使用示例之 后，我的第一感受就是：可能能起作用，但用起来实在是太难看了。限于篇幅，我就不在这里列出它的例子，有兴趣了解其实现究竟的，可前往观之。对于Grails MongoDB plugin的基本使用，其实跟使用Domain Class一样： 安装插件：grails install-plugin gorm-mongodb 在Config.groovy里配置数据源： mongodb { host = '192.168.1.36' port = 27017 database = 'test' } 创建MongoDB领域类：grails create-mongodb-class 领域类名 象平常一样编辑领域类 产生脚手架代码：grails generate-all 领域类名 是不是非常简单？你还可以利用grails的template机制来定制你自己的MongoDB领域类：在工程的src\templates \artifacts目录下创建一个MongoDBClass.groovy文件，如： @artifact.package@import grails.plugins.mongodb.MongoEntity [...]]]></description>
			<content:encoded><![CDATA[<p>相信<a href="http://www.mongodb.org/" target="_blank">MongoDB</a>的名头不少人 已经听说过了，虽然已有针对它的<a href="http://github.com/mongodb/mongo-java-driver" target="_blank">Java驱动</a>，但我敢打保票，只要你用过一次，很快就会怀念使用GORM的好时光。拜Grails的插件架构所赐，对于Grails项目来说，这不再是幻想。目前在Grails社区至少已经有两个针对MongoDB的插件：<a href="http://grails.org/plugin/mongodb-tools" target="_blank">MongoDB Tools</a>和<a href="http://www.grails.org/plugin/gorm-mongodb" target="_blank">Grails  MongoDB plugin</a>，我们该选择哪一个呢？</p>
<p>在查看了两个插件的信息后，我坚定地选择了后者：<a href="http://www.grails.org/plugin/gorm-mongodb" target="_blank">Grails MongoDB plugin</a>。 原因无它：完全保留了GORM的使用习惯，而且特性几乎一样：</p>
<blockquote>
<ul>
<li>实例方法：save、delete</li>
<li>类方法：get、find、findAll、delete、deleteAll、exists、count、list</li>
<li>诸如findAllByNameAndDegreeBetween(&#8230;)这样的动态查找器</li>
<li>支持约束和验证</li>
<li>支持自动时辍：dateCreated和lastUpdated</li>
<li>Gorm事件：beforeSave、afterSave、beforeDelete、afterDelete（还有Morphia支持的 afterLoad）</li>
<li>支持MongoDB 1.4和1.5</li>
<li>提供了注入所有必需字段和Morphia注解的AST Transformations</li>
<li>支持延迟引用</li>
<li>支持generate-all</li>
</ul>
</blockquote>
<p><span id="more-5285"></span><br />
注意最后一个点，这个插件甚至支持了脚手架代码的产生！反观<a href="http://grails.org/plugin/mongodb-tools" target="_blank">MongoDB Tools</a>，看完它的<a href="http://github.com/mpriatel/mongodb-grails" target="_blank">使用示例</a>之 后，我的第一感受就是：可能能起作用，但用起来实在是太难看了。限于篇幅，我就不在这里列出它的例子，有兴趣了解其实现究竟的，可前往观之。对于<a href="http://www.grails.org/plugin/gorm-mongodb" target="_blank">Grails  MongoDB plugin</a>的基本使用，其实跟使用Domain Class一样：</p>
<ul>
<li>安装插件：grails install-<a href="http://www.iwanna.cn/tags/plugin/" class="st_tag internal_tag" rel="tag" title="标签 Plugin 下的日志">plugin</a> gorm-<a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">mongodb</a></li>
<li>在Config.groovy里配置数据源：</li>
<blockquote>
<pre title="code">            mongodb {
                host = '192.168.1.36'
                port = 27017
                database = 'test'
            }
</pre>
</blockquote>
<li>创建MongoDB领域类：grails create-mongodb-class 领域类名</li>
<li>象平常一样编辑领域类</li>
<li>产生脚手架代码：grails generate-all 领域类名</li>
</ul>
<p>是不是非常简单？你还可以利用grails的template机制来定制你自己的MongoDB领域类：在工程的src\templates \artifacts目录下创建一个MongoDBClass.groovy文件，如：</p>
<pre title="code">@artifact.package@import grails.plugins.mongodb.MongoEntity

@MongoEntity
class @artifact.name@ {

    Date dateCreated
    Date lastUpdated

    int version

    static constraints = {
    }
}
</pre>
<p>如此，你每次创建出的MongoDB领域类就都会包含上述3个字段，即具有时辍和版本。</p>
<p>除了这种高级别的抽象，要是你想访问底层支持类，如Morphia或MongoDB的Java驱动类，这个插件同样提供了支持，相关细节请查看<a href="http://jkuehn.github.com/gorm-mongodb/guide/5.%20Low%20Level%20Access.html" target="_blank">这 篇文档</a>。其余信息则可以通过它的<a href="http://jkuehn.github.com/gorm-mongodb/" target="_blank">用户参考</a>了解。</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5285/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5285/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5285/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5285/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5285/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5285/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java编程三十条规则</title>
		<link>http://www.iwanna.cn/archives/2010/07/04/4353/</link>
		<comments>http://www.iwanna.cn/archives/2010/07/04/4353/#comments</comments>
		<pubDate>Sun, 04 Jul 2010 07:33:21 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=4353</guid>
		<description><![CDATA[(1) 类名首字母应该大写。字段、方法以及对象（句柄）的首字母应小写。对于所有标识符，其中包含的所有单词都应紧靠在一起，而且大写中间单词的首字 母。例如： ThisIsAClassName thisIsMethodOrFieldName 若在定义中出现了常数初始化字符，则大写static final基本类型标识符中的所有字母。这样便可标志出它们属于编译期的常数。 Java包（Package）属于一种特殊情况：它们全都是小写字母，即便中间的单词亦是如此。对于域名扩展名称，如com，org，net或者edu 等，全部都应小写（这也是Java 1.1和Java 1.2的区别之一）。 (2) 为了常规用途而创建一个类时，请采取“经典形式”，并包含对下述元素的定义： equals() hashCode() toString() clone()（implement Cloneable） implement Serializable (3) 对于自己创建的每一个类，都考虑置入一个main()，其中包含了用于测试那个类的代码。为使用一个项目中的类，我们没必要删除测试代码。若 进行了任何形式的改动，可方便地返回测试。这些代码也可作为如何使用类的一个示例使用。 (4) 应将方法设计成简要的、功能性单元，用它描述和实现一个不连续的类接口部分。理想情况下，方法应简明扼要。若长度很大，可考虑通过某种方式将 其分割成较短的几个方法。这样做也便于类内代码的重复使用（有些时候，方法必须非常大，但它们仍应只做同样的一件事情）。 (5) 设计一个类时，请设身 处地为客户程序员考虑一下（类的使用方法应该是非常明确的）。然后，再设身处地为管理代码的人考虑一下（预计有可能进行哪些形式的修改，想想用什么方法可 把它们变得更简单）。 (6) 使类尽可能短小精悍，而且只解决一个特定的问题。下面是对类设计的一些建议： ■一个复杂的开关语句：考虑采用“多形”机制 ■数量众多的方法涉及到类型差别极大的操作：考虑用几个类来分别实现 ■许多成员变量在特征上有很大的差别：考虑使用几个类 。 (7) 让一切东西都尽可能地“私有”——private。可使库的某一部分“公共化”（一个方法、类或者一个字段等等），就永远不能把它拿出。若强 行拿出，就可能破坏其他人现有的代码，使他们不得不重新编写和设计。若只公布自己必须公布的，就可放心大胆地改变其他任何东西。在多线程环境中，隐私是特 别重要的一个因素——只有private字段才能在非同步使用的情况下受到保护。 (8) 谨惕“巨大对象综合症”。对一些习惯于顺序编程思维、且初涉OOP领域的新手，往往喜欢先写一个顺序执行的程序，再把它嵌入一个或两个巨大的 对象里。根据编程原理，对象表达的应该是应用程序的概念，而非应用程序本身。 (9) 若不得已进行一些不太雅观的编程，至少应该把那些代码置于一个类的内部。 (10) 任何时候只要发现类与类之间结合得非常紧密，就需要考虑是否采用内部类，从而改善编码及维护工作（参见第14章14.1.2小节的“用内部 类改进代码”）。 (11) 尽可能细致地加上释，并用javadoc注释文档语法生成自己的程序文档。 (12) 避免使用“魔术数字”，这些数字很难与代码很好地配合。如以后需要修改它，无疑会成为一场噩梦，因为根本不知道“100”到底是指“数组大 小”还是“其他全然不同的东西”。所以，我们应创建一个常数，并为其使用具有说服力的描述性名称，并在整个程序中都采用常数标识符。这样可使程序更易理解 以及更易维护。 (13) 涉及构建器和异常的时候，通常希望重新丢弃在构建器中捕获的任何异常——如果它造成了那个对象的创建失败。这样一来，调用者就不会以为那个 对象已正确地创建，从而盲目地继续。 (14) 当客户程序员用完对象以后，若你的类要求进行任何清除工作，可考虑将清除代码置于一个良好定义的方法里，采用类似于cleanup()这样 的名字，明确表明自己的用途。除此以外，可在类内放置一个boolean（布尔）标记，指出对象是否已被清除。在类的finalize()方法里，请确定 对象已被清除，并已丢弃了从RuntimeException继承的一个类（如果还没有的话），从而指出一个编程错误。在采取象这样的方案之前，请确定 finalize()能够在自己的系统中工作（可能需要调用System.runFinalizersonExit(true)，从而确保 这一行为）。 (15) 在一个特定的作用域内，若一个对象必须清除（非由垃圾收集机制处理），请采用下述方法：初始化对象；若成功，则立即进入一个含有 finally从句的try块，开始清除工作。 (16) 若在初始化过程中需要覆盖（取消）finalize()，请记住调用super.finalize()（若Object属于我们的直接超 类，则无此必要）。在对finalize()进行覆盖的过程中，对super.finalize()的调用应属于最后一个行动，而不应是第一个行动，这样 可确保在需要基础类组件的时候它们依然有效。 (17) 创建大小固定的对象集合时，请将它们传输至一个数组（若准备从一个方法里返回这个集合，更应如此操作）。这样一来，我们就可享受到数组在编 译期进行类型检查的好处。此外，为使用它们，数组的接收者也许并不需要将对象“造型”到数组里。 (18) 尽量使用interfaces，不要使用abstract类。若已知某样东西准备成为一个基础类，那么第一个选择应是将其变成一个 interface（接口）。只有在不得不使用方法定义或者成员变量的时候，才需要将其变成一个abstract（抽象）类。接口主要描述了客户希望做什 么事情，而一个类则致力于（或允许）具体的实施细节。 (19) 在构建器内部，只进行那些将对象设为正确状态所需的工作。尽可能地避免调用其他方法，因为那些方法可能被其他人覆盖或取消，从而在构建过程 中产生不可预知的结果（参见第7章的详细说明）。 (20) 对象不应只是简单地容纳一些数据；它们的行为也应得到良好的定义。 [...]]]></description>
			<content:encoded><![CDATA[<p>(1) 类名首字母应该大写。字段、方法以及对象（句柄）的首字母应小写。对于所有标识符，其中包含的所有单词都应紧靠在一起，而且大写中间单词的首字 母。例如：</p>
<p>ThisIsAClassName<br />
thisIsMethodOrFieldName</p>
<p>若在定义中出现了常数初始化字符，则大写static final基本类型标识符中的所有字母。这样便可标志出它们属于编译期的常数。<br />
Java包（Package）属于一种特殊情况：它们全都是小写字母，即便中间的单词亦是如此。对于域名扩展名称，如com，org，net或者edu 等，全部都应小写（这也是Java 1.1和Java 1.2的区别之一）。<br />
<span id="more-4353"></span><br />
(2) 为了常规用途而创建一个类时，请采取“经典形式”，并包含对下述元素的定义：</p>
<p>equals()<br />
hashCode()<br />
toString()<br />
clone()（implement Cloneable）<br />
implement Serializable</p>
<p>(3) 对于自己创建的每一个类，都考虑置入一个main()，其中包含了用于测试那个类的代码。为使用一个项目中的类，我们没必要删除测试代码。若 进行了任何形式的改动，可方便地返回测试。这些代码也可作为如何使用类的一个示例使用。</p>
<p>(4) 应将方法设计成简要的、功能性单元，用它描述和实现一个不连续的类接口部分。理想情况下，方法应简明扼要。若长度很大，可考虑通过某种方式将 其分割成较短的几个方法。这样做也便于类内代码的重复使用（有些时候，方法必须非常大，但它们仍应只做同样的一件事情）。 (5) 设计一个类时，请设身 处地为客户程序员考虑一下（类的使用方法应该是非常明确的）。然后，再设身处地为管理代码的人考虑一下（预计有可能进行哪些形式的修改，想想用什么方法可 把它们变得更简单）。</p>
<p>(6) 使类尽可能短小精悍，而且只解决一个特定的问题。下面是对类设计的一些建议：</p>
<p>■一个复杂的开关语句：考虑采用“多形”机制</p>
<p>■数量众多的方法涉及到类型差别极大的操作：考虑用几个类来分别实现</p>
<p>■许多成员变量在特征上有很大的差别：考虑使用几个类 。</p>
<p>(7) 让一切东西都尽可能地“私有”——private。可使库的某一部分“公共化”（一个方法、类或者一个字段等等），就永远不能把它拿出。若强 行拿出，就可能破坏其他人现有的代码，使他们不得不重新编写和设计。若只公布自己必须公布的，就可放心大胆地改变其他任何东西。在多线程环境中，隐私是特 别重要的一个因素——只有private字段才能在非同步使用的情况下受到保护。</p>
<p>(8) 谨惕“巨大对象综合症”。对一些习惯于顺序编程思维、且初涉OOP领域的新手，往往喜欢先写一个顺序执行的程序，再把它嵌入一个或两个巨大的 对象里。根据编程原理，对象表达的应该是应用程序的概念，而非应用程序本身。</p>
<p>(9) 若不得已进行一些不太雅观的编程，至少应该把那些代码置于一个类的内部。</p>
<p>(10) 任何时候只要发现类与类之间结合得非常紧密，就需要考虑是否采用内部类，从而改善编码及维护工作（参见第14章14.1.2小节的“用内部 类改进代码”）。</p>
<p>(11) 尽可能细致地加上释，并用javadoc注释文档语法生成自己的程序文档。</p>
<p>(12) 避免使用“魔术数字”，这些数字很难与代码很好地配合。如以后需要修改它，无疑会成为一场噩梦，因为根本不知道“100”到底是指“数组大 小”还是“其他全然不同的东西”。所以，我们应创建一个常数，并为其使用具有说服力的描述性名称，并在整个程序中都采用常数标识符。这样可使程序更易理解 以及更易维护。</p>
<p>(13) 涉及构建器和异常的时候，通常希望重新丢弃在构建器中捕获的任何异常——如果它造成了那个对象的创建失败。这样一来，调用者就不会以为那个 对象已正确地创建，从而盲目地继续。</p>
<p>(14) 当客户程序员用完对象以后，若你的类要求进行任何清除工作，可考虑将清除代码置于一个良好定义的方法里，采用类似于cleanup()这样 的名字，明确表明自己的用途。除此以外，可在类内放置一个boolean（布尔）标记，指出对象是否已被清除。在类的finalize()方法里，请确定 对象已被清除，并已丢弃了从RuntimeException继承的一个类（如果还没有的话），从而指出一个编程错误。在采取象这样的方案之前，请确定 finalize()能够在自己的系统中工作（可能需要调用System.runFinalizers<em>onExit</em>(true)，从而确保 这一行为）。</p>
<p>(15) 在一个特定的作用域内，若一个对象必须清除（非由垃圾收集机制处理），请采用下述方法：初始化对象；若成功，则立即进入一个含有 finally从句的try块，开始清除工作。</p>
<p>(16) 若在初始化过程中需要覆盖（取消）finalize()，请记住调用super.finalize()（若Object属于我们的直接超 类，则无此必要）。在对finalize()进行覆盖的过程中，对super.finalize()的调用应属于最后一个行动，而不应是第一个行动，这样 可确保在需要基础类组件的时候它们依然有效。</p>
<p>(17) 创建大小固定的对象集合时，请将它们传输至一个数组（若准备从一个方法里返回这个集合，更应如此操作）。这样一来，我们就可享受到数组在编 译期进行类型检查的好处。此外，为使用它们，数组的接收者也许并不需要将对象“造型”到数组里。</p>
<p>(18) 尽量使用interfaces，不要使用abstract类。若已知某样东西准备成为一个基础类，那么第一个选择应是将其变成一个 interface（接口）。只有在不得不使用方法定义或者成员变量的时候，才需要将其变成一个abstract（抽象）类。接口主要描述了客户希望做什 么事情，而一个类则致力于（或允许）具体的实施细节。</p>
<p>(19) 在构建器内部，只进行那些将对象设为正确状态所需的工作。尽可能地避免调用其他方法，因为那些方法可能被其他人覆盖或取消，从而在构建过程 中产生不可预知的结果（参见第7章的详细说明）。</p>
<p>(20) 对象不应只是简单地容纳一些数据；它们的行为也应得到良好的定义。</p>
<p>(21) 在现成类的基础上创建新类时，请首先选择“新建”或“创作”。只有自己的设计要求必须继承时，才应考虑这方面的问题。若在本来允许新建的场 合使用了继承，则整个设计会变得没有必要地复杂。</p>
<p>(22) 用继承及方法覆盖来表示行为间的差异，而用字段表示状态间的区别。一个非常极端的例子是通过对不同类的继承来表示颜色，这是绝对应该避免 的：应直接使用一个“颜色”字段。</p>
<p>(23) 为避免编程时遇到麻烦，请保证在自己类路径指到的任何地方，每个名字都仅对应一个类。否则，编译器可能先找到同名的另一个类，并报告出错消 息。若怀疑自己碰到了类路径问题，请试试在类路径的每一个起点，搜索一下同名的.class文件。</p>
<p>(24) 在Java 1.1 AWT中使用事件“适配器”时，特别容易碰到一个陷阱。若覆盖了某个适配器方法，同时拼写方法没有特别讲究，最后的结 果就是新添加一个方法，而不是覆盖现成方法。然而，由于这样做是完全合法的，所以不会从编译器或运行期系统获得任何出错提示——只不过代码的工作就变得不 正常了。</p>
<p>(25) 用合理的设计方案消除“伪功能”。也就是说，假若只需要创建类的一个对象，就不要提前限制自己使用应用程序，并加上一条“只生成其中一个” 注释。请考虑将其封装成一个“独生子”的形式。若在主程序里有大量散乱的代码，用于创建自己的对象，请考虑采纳一种创造性的方案，将些代码封装起来。</p>
<p>(26) 警惕“分析瘫痪”。请记住，无论如何都要提前了解整个项目的状况，再去考察其中的细节。由于把握了全局，可快速认识自己未知的一些因素，防 止在考察细节的时候陷入“死逻辑”中。</p>
<p>(27) 警惕“过早优化”。首先让它运行起来，再考虑变得更快——但只有在自己必须这样做、而且经证实在某部分代码中的确存在一个性能瓶颈的时候， 才应进行优化。除非用专门的工具分析瓶颈，否则很有可能是在浪费自己的时间。性能提升的隐含代价是自己的代码变得难于理解，而且难于维护。</p>
<p>(28) 请记住，阅读代码的时间比写代码的时间多得多。思路清晰的设计可获得易于理解的程序，但注释、细致的解释以及一些示例往往具有不可估量的价 值。无论对你自己，还是对后来的人，它们都是相当重要的。如对此仍有怀疑，那么请试想自己试图从联机Java文档里找出有用信息时碰到的挫折，这样或许能 将你说服。</p>
<p>(29) 如认为自己已进行了良好的分析、设计或者实施，那么请稍微更换一下思维角度。试试邀请一些外来人士——并不一定是专家，但可以是来自本公司 其他部门的人。请他们用完全新鲜的眼光考察你的工作，看看是否能找出你一度熟视无睹的问题。采取这种方式，往往能在最适合修改的阶段找出一些关键性的问 题，避免产品发行后再解决问题而造成的金钱及精力方面的损失。</p>
<p>(30) 良好的设计能带来最大的回报。简言之，对于一个特定的问题，通常会花较长的时间才能找到一种最恰当的解决方案。但一旦找到了正确的方法，以 后的工作就轻松多了，再也不用经历数小时、数天或者数月的痛苦挣扎。我们的努力工作会带来最大的回报（甚至无可估量）。而且由于自己倾注了大量心血，最终 获得一个出色的设计方案，成功的快感也是令人心动的。坚持抵制草草完工的诱惑——那样做往往得不偿失<br />
对你有帮助没呀？？？呵呵！~！</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/07/04/4353/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/07/04/4353/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/07/04/4353/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/07/04/4353/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/07/04/4353/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/07/04/4353/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java程序员十戒</title>
		<link>http://www.iwanna.cn/archives/2009/08/22/2183/</link>
		<comments>http://www.iwanna.cn/archives/2009/08/22/2183/#comments</comments>
		<pubDate>Sat, 22 Aug 2009 15:49:17 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=2183</guid>
		<description><![CDATA[Java程序员有许多应遵循的守则或最佳实践方式。本文概述了每个开发者最应该遵循的10条守则或戒律，如果不遵循它们，将会导致灾难性后果。 1. 为代码添加注释（Add comments to your code）. – 每个人都知道这一点，但不是每个人都会这么做。你有多少次“忘记”添加注释了？确实，注释不会为你的程序增加任何函数功能。但是，有多少次，看到2周前写 的代码，你都记不起它是干什么的？你很幸运，那些未注释的代码是你自己写的，你脑海中还会有残存的印象。非常不幸，大多时候，代码是别人写的，并且那个人 很可能已经离开公司了。有句谚语说的好：“有来有往，互惠互利”，因此程序员应该体谅彼此（还有你自己），给你的代码加上注释。 2. 不要把简单事情复杂化（Do not complicate things）. – 我曾经这么做过，我相信你也一样。开发者都倾向于采用复杂方式解决简单问题。我们在一个只有5个用户的系统中引入EJB，为一个并不需要框架的应用实现一 套框架，采用属性文件、采用面向对象解决方案、使用线程，而这些根本用不着。为什么会这么做？一些人可能不知道有更好的解决方案，但另一些人可能故意这样 做来学习新知识，或仅仅是因为有趣。对那些不知道更好解决方案的人，要多听有经验程序员的建议。对于那些纯粹出于个人目的而将设计复杂化的人，我建议你要 更加专业一点。 3. 记住 － “越少越好”并非总是如此(Keep in Mind – &#8220;Less is more&#8221; is not always better). – 高效率的代码是件好事，但很多情况下，并非代码行数越少效率就越高。看下面这个“简单”的例子： if(newStatusCode.equals("SD") &#38;&#38; (sellOffDate == null &#124;&#124; todayDate.compareTo(sellOffDate)&#60;0 &#124;&#124; (lastUsedDate != null &#38;&#38; todayDate.compareTo(lastUsedDate)&#62;0)) &#124;&#124; (newStatusCode.equals("OBS") &#38;&#38; (OBSDate == [...]]]></description>
			<content:encoded><![CDATA[<p>Java程序员有许多应遵循的守则或最佳实践方式。本文概述了每个开发者最应该遵循的10条守则或戒律，如果不遵循它们，将会导致灾难性后果。<br />
<span id="more-2183"></span><br />
<strong>1. 为代码添加注释（Add comments to your code）.</strong> – 每个人都知道这一点，但不是每个人都会这么做。你有多少次“忘记”添加注释了？确实，注释不会为你的程序增加任何函数功能。但是，有多少次，看到2周前写 的代码，你都记不起它是干什么的？你很幸运，那些未注释的代码是你自己写的，你脑海中还会有残存的印象。非常不幸，大多时候，代码是别人写的，并且那个人 很可能已经离开公司了。有句谚语说的好：“有来有往，互惠互利”，因此程序员应该体谅彼此（还有你自己），给你的代码加上注释。</p>
<p><strong>2. 不要把简单事情复杂化（Do not complicate things）.</strong> – 我曾经这么做过，我相信你也一样。开发者都倾向于采用复杂方式解决简单问题。我们在一个只有5个用户的系统中引入EJB，为一个并不需要框架的应用实现一 套框架，采用属性文件、采用面向对象解决方案、使用线程，而这些根本用不着。为什么会这么做？一些人可能不知道有更好的解决方案，但另一些人可能故意这样 做来学习新知识，或仅仅是因为有趣。对那些不知道更好解决方案的人，要多听有经验程序员的建议。对于那些纯粹出于个人目的而将设计复杂化的人，我建议你要 更加专业一点。</p>
<p><strong>3. 记住 － “越少越好”并非总是如此(Keep in Mind – &#8220;Less is more&#8221; is not always better).</strong> – 高效率的代码是件好事，但很多情况下，并非代码行数越少效率就越高。看下面这个“简单”的例子：</p>
<pre>if(newStatusCode.equals("SD") &amp;&amp; (sellOffDate == null ||
todayDate.compareTo(sellOffDate)&lt;0 || (lastUsedDate != null &amp;&amp;
todayDate.compareTo(lastUsedDate)&gt;0)) ||
(newStatusCode.equals("OBS") &amp;&amp; (OBSDate == null ||
todayDate.compareTo(OBSDate)&lt;0))){
		newStatusCode = "NYP";
}</pre>
<p>指出这个if条件是什么有多困难？再设想一下，写这段代码的人并没遵循第1条 － <em>为代码添加注释</em>。</p>
<p>把if条件分解成2个if语句不是更容易理解吗？现在让我们看一下修改过的代码：</p>
<pre>if(newStatusCode.equals("SD") &amp;&amp; (sellOffDate == null ||
todayDate.compareTo(sellOffDate)&lt;0 || (lastUsedDate != null &amp;&amp;
todayDate.compareTo(lastUsedDate)&gt;0))){
		newStatusCode = "NYP";
}else
if(newStatusCode.equals("OBS") &amp;&amp; (OBSDate == null ||
todayDate.compareTo(OBSDate)&lt;0))
{
		newStatusCode = "NYP";
}</pre>
<p>这样可读性不是更好吗？的确，我们写了重复语句；的确，我们多写了一个if和2个大括号；但是代码确实更加易读、更加容易理解了！</p>
<p><strong>4. 不要“硬编码&#8221;（No hard coding please）. </strong>– 由于时间紧迫，开发者总是会忘记或故意忽略这一条。然而另一种可能是，遵循这条戒律，我们就不会陷入“时间紧迫”的困境。定义一个static final 变量，增加一行代码，又能花多长时间呢？譬如：</p>
<pre>public class A {

		public static final String S_CONSTANT_ABC = "ABC";

		public boolean methodA(String sParam1){

			if (A.S_CONSTANT_ABC.equalsIgnoreCase(sParam1)){
				return true;
			}
			return false;
		}
}</pre>
<p>现在，每次需要比较字符串“ABC”与某个变量的时候，我们只要引用 <tt>A.S_CONSTANT_ABC 即可，而不必记住它本身是什么。对这个常量的修改也非常方便，改一个地方即可，而不必在全部代码中查找。</tt></p>
<p><strong><strong>5. 不要发明你自己的框架（Do not invent your own frameworks）.</strong> </strong>– 不夸张地讲，已经有几千个框架存在了，大多数还是开源的。很多框架都是极完美的解决方案，并已被用到成千的系统中。我们只要关注最新的流行的框架，至少表 面上要熟悉一下。一个最成功的、也是被广泛使用的例子是Struts框架，这个开源的web框架是建立web系统的极佳选择，不要试图构造你自己的 Struts版本，会累死的。但你必须记住第2条（译注：原文是“第3条”，显然不对）戒律 —— 不要把简单事情复杂化。如果你要开发的系统只有3个界面，就不要用Struts. 对于这样一个系统，没有足够的需要被“控制”的东西（译注：Struts将界面做MVC划分，C即controller，所以作者说there isn&#8217;t much &#8220;controlling&#8221; required）。</p>
<p><strong>6. 对Print行或字符串说不（Say no to Print lines and String Concatenations）.</strong> – 我知道为了调试方便，程序员喜欢到处用<tt>System.out.println</tt> ,然后对自己说过一会就删掉。但我们常常忘记删掉这些行或不愿删掉，我们用<tt>System.out.println</tt> 做测试，为什么测完后还要去改代码？这很可能导致误删一行我们需要的代码。不要低估<tt>System.out.println 的危害，看下面代码：</tt></p>
<pre>public class BadCode {
	public static void calculationWithPrint(){
		double someValue = 0D;
		for (int i = 0; i &lt; 10000; i++) {
			System.out.println(someValue = someValue + i);
		}
	}
	public static void calculationWithOutPrint(){

			double someValue = 0D;
			for (int i = 0; i &lt; 10000; i++) {
				someValue = someValue + i;
			}

	}
	public static void main(String [] n) {
		BadCode.calculationWithPrint();
		BadCode.calculationWithOutPrint();
	}
}</pre>
<p>下面表格可以看出，<tt>calculationWithOutPrint()</tt> 方法执行时间是0.001204 s. 作为对比，calculationWithPrint() 方法居然需要令人难以置信的10.52 s来执行！</p>
<p><img src="http://www.developer.com/img/2006/06/Ten1.jpg" alt="" /></p>
<p>(若你想知道怎么做一个这样的表，请阅读我的另一篇文章&#8221;<a href="http://www.iwanna.cn/tags/java/" class="st_tag internal_tag" rel="tag" title="标签 Java 下的日志">Java</a> Profiling with WSAD&#8221; <a href="http://www.developer.com/java/ent/article.php/3598166" target="_blank">Java Profiling with WSAD</a> )</p>
<p>为了避免CPU浪费，最好的办法是引入一个包装的方法，如下：</p>
<pre>public class BadCode {

		public static final int DEBUG_MODE = 1;
		public static final int PRODUCTION_MODE = 2;

	public static void calculationWithPrint(int logMode){
		double someValue = 0D;
		for (int i = 0; i &lt; 10000; i++) {
			someValue = someValue + i;
			myPrintMethod(logMode, someValue);
		}
	}

	public static void myPrintMethod(int logMode, double value) {
		if (logMode &gt; BadCode.DEBUG_MODE) {	return; }
		System.out.println(value);
	}
	public static void main(String [] n) {
		BadCode.calculationWithPrint(BadCode.PRODUCTION_MODE);
		}
}</pre>
<p>字符串(String)连接是另一种CPU浪费方式，看下面的例子：</p>
<pre>public static void concatenateStrings(String startingString) {
		for (int i = 0; i &lt; 20; i++) {
			startingString = startingString + startingString;
		}
	}

	public static void concatenateStringsUsingStringBuffer(
String startingString) {
		StringBuffer sb = new StringBuffer();
		sb.append(startingString);
			for (int i = 0; i &lt; 20; i++) {
				sb.append(sb.toString());
			}
}</pre>
<p>从下面表格可以看出使用 <tt>StringBuffer只要花 </tt>0.01 s 而使用String 连接需要0.08 s，选择哪种应该很明显了。</p>
<p><img src="http://www.developer.com/img/2006/06/Ten2.jpg" alt="" /></p>
<p><strong>7. 注意图形用户界面（Pay attention to the GUI）.</strong> – 无论听上去多荒谬，但有一点我注意过多次了：图形用户界面（GUI）对于商业用户而言与程序功能及执行效率一样重要。GUI对于应用程序的成功至关重要。 IT管理者（译注：这里应该是指程序开发方的IT management）常常忽略GUI的重要性，很多公司为了省钱而不雇佣web设计人员，而这些设计人员有足够的经验来设计“用户友好”的应用软件。 Java程序员不得不依赖他们有限的HMTL知识。我见过非常多对“计算机友好”而非对“用户友好”的应用程序，同时精通软件开发和用户界面开发的开发者 非常少见。 如果你是一位不幸被指派做界面开发的Java程序员，你要遵循下面3条规则：</p>
<ol>
<li>不要重新发明轮子。去看那些类似应用系统的界面。</li>
<li>首先建立一个原型。这一步非常关键。客户喜欢提前看到他们要用的东西。同样你可以得到他们的反馈，而不是你辛辛苦苦做出来一个客户不喜欢的东西。</li>
<li>试戴用户的帽子。换句话说，站在用户的角度查看需求。譬如，一个统计的界面可以分页，也可以不分页。作为开发者，很可能会忽略分页，因为这会减少很多麻烦；而站在客户角度，这就不是一个好的方案，因为数据可能多达几百行。</li>
</ol>
<div><strong>8. 提前准备需求文档（Always Prepare Document Requirements）.</strong> – 每项业务需求都记入文档。这在童话故事中可能实现，而现实中很难做到。无论时间多么紧迫，无论截止日期如何迫近，你必须确保业务需求被记录下来。（译注：这条明显悖于敏捷开发的观念，大家要独立思考，甄别是非）</div>
<div>
<p><strong><strong>9. 单元测试，单元测试，单元测试 （Unit-test. Unit-test. Unit-test）.</strong> </strong>– 我不准备讨论如何单元测试的细节，我只是想说这必须要做。这是编程中最基本的规则了，尤其不能忽略。如果你同事能为你的代码创建一个测试计划，那就再好不过了；如果不能，那就要自己做。做单元测试计划时，遵循下面原则：</p>
<ol>
<li>编码前就写单元测试</li>
<li>保留单元测试的注释</li>
<li>对任何“有趣的”公共方法都要做单元测试（“有趣的”是指除了像最常见的getter/setter这类方法外的方法，但包含有自己内容的getter/setter 方法）</li>
</ol>
</div>
<div>
<p><strong>10. 记住：质量，而非数量（Remember – quality, not quantity）.</strong> &#8211; 不要待的太晚（除非有必要）。我知道有时因为产品问题，截止期限或其他突发事件，不能按时下班。但经理不会因为你为一般问题待的太晚而感激或奖励你；他们会为有质量的工作而感激你。如果你遵循上面的列的原则，你就会写更健壮的、少bug的程序。这才是你最应该做的。</p>
<h3>结论</h3>
<p>本文中我总结了Java程序员最应注意的10项守则。仅仅知道是不够的，还要遵循它们。希望这些守则能让我们做更加专业的程序员。</p></div>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2009. |
<a href="http://www.iwanna.cn/archives/2009/08/22/2183/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2009/08/22/2183/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2009/08/22/2183/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2009/08/22/2183/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2009/08/22/2183/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2009/08/22/2183/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>10个基于Java的CMS网站内容管理系统</title>
		<link>http://www.iwanna.cn/archives/2009/05/03/931/</link>
		<comments>http://www.iwanna.cn/archives/2009/05/03/931/#comments</comments>
		<pubDate>Sun, 03 May 2009 08:57:24 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Assemble]]></category>
		<category><![CDATA[CMS]]></category>
		<category><![CDATA[Marrow]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=931</guid>
		<description><![CDATA[在开始研究 java CMS之前，我们先要了解什么是CMS。CMS — Content Management Systems，内容管理系统，简单的说，就是一个帮助进行网站内容管理的系统。CMS通常包含两部分：内容管理程序(Content Management Application ,CMA)和内容发布程序(Content Delivery Application ,CDA)，内容管理程序可以帮助网站管理员轻松的实现网站文章的创建、编辑和删除操作，内容发布程序则可以编辑文章并在网站上发布它们。 一个完整的CMS通常包含一个在线的发布、排版、版本控制，以及列表、搜索、恢复等功能模块。近年来大量涌现的企业网站管理系统，则增加了新闻管 理、使用手册、在线帮助、销售手册等功能。难以避免的，功能强大的CMS往往有着高昂的售价，预算不足的用户很希望找到一款好用且免费的管理系统。现在已 经出现了许多基于java的开源CMS系统，本文挑选了10个最强大、最易用的CMS，向大家做一个简要介绍。 1. Alfresco Alfresco是一个开源的企业网站内容管理系统，它提供了文档管理、多人协作、记录管理、知识管理网页内容和图像管理等功能。它使用Spring、 Hibernate、 Lucene 和JSF等最新java技术构建了模块化的系统架构。 Alfresco官方网站 中文教程 2. DotCMS DotCMS是一个开源的 企业级内容管理系统，它融入了电子商 务、个性化设置、客户关系管理工具等功能，它可以方便的建立基于各种关系的数据结构和数据库，它可以使用模板快速创建页面，并且提供了一个强大的所见即所 得(WYSIWYG)编辑器。用户可以使用加载外部模块的功能快速的建立Ajax应用、搜索、MP3播放器、幻灯片和相册等功能。 DotCMS官方网站 中文安装教程 3. Magnolia Magnolia是一个老牌的java内容管理系统，目前已经发布了第四版。它的独特之处在于可以定制内容模型，以返回数组形式来搞定各种不确定的 功能。它遵循W3C标准并且在搜索引擎优化上有许多优势。同时它支持java内容仓库( java content repositories , JCR) 的API。 Magnolia官方网站 4. OpenCms 它提供了一套建立和维护网站的方便的工具。在内容建设方面，它拥有一个易于使用的界面和所见即所得编辑器，在网页生成上它使用了一个先进的页面模板。 OpenCMS官方网站 中文网站 6. AtLeap Blandware AtLeap是一个多语种的免费Java内容管理系统，它包含了全文搜索引擎，可以算是一个能让你方便的编写应用的网站框架。 Atleap官方网站 7. Fedora [...]]]></description>
			<content:encoded><![CDATA[<p>在开始研究 <a href="http://www.iwanna.cn/tags/java/" class="st_tag internal_tag" rel="tag" title="标签 Java 下的日志">java</a> CMS之前，我们先要了解什么是CMS。<a href="http://www.iwanna.cn/tags/cms/" class="st_tag internal_tag" rel="tag" title="标签 CMS 下的日志">CMS</a> — Content Management Systems，内容管理系统，简单的说，就是一个帮助进行网站内容管理的系统。CMS通常包含两部分：内容管理程序(Content Management Application ,CMA)和内容发布程序(Content Delivery Application ,CDA)，内容管理程序可以帮助网站管理员轻松的实现网站文章的创建、编辑和删除操作，内容发布程序则可以编辑文章并在网站上发布它们。</p>
<p style="text-align: center;"><img src="http://oncoding.net/uploads/allimg/090503/12551M334-0.jpg" border="0" alt="" width="400" height="300" /></p>
<p><span id="more-931"></span><br />
一个完整的CMS通常包含一个在线的发布、排版、版本控制，以及列表、搜索、恢复等功能模块。近年来大量涌现的企业网站管理系统，则增加了新闻管 理、使用手册、在线帮助、销售手册等功能。难以避免的，功能强大的CMS往往有着高昂的售价，预算不足的用户很希望找到一款好用且免费的管理系统。现在已 经出现了许多基于java的开源CMS系统，本文挑选了10个最强大、最易用的CMS，向大家做一个简要介绍。</p>
<h3>1. Alfresco</h3>
<p style="text-align: center;"><img class="size-full wp-image-8576 aligncenter" src="http://oncoding.net/uploads/allimg/090503/12515K394-0.png" alt="alfresco" width="260" height="220" /></p>
<p>Alfresco是一个<span style="font-weight: bold;">开源</span>的企业网站内容管理系统，它提供了文档管理、多人协作、记录管理、知识管理网页内容和图像管理等功能。它使用Spring、 Hibernate、 Lucene 和JSF等最新java技术构建了模块化的系统架构。</p>
<p><a href="http://www.alfresco.com/" target="_blank">Alfresco官方网站</a> <a href="http://blog.csdn.net/alfresco/" target="_blank">中文教程<br />
</a></p>
<h3>2. DotCMS</h3>
<p style="text-align: center;"><img class="size-full wp-image-8577 aligncenter" src="http://oncoding.net/uploads/allimg/090503/12515M4B-1.jpg" alt="dotcms" width="396" height="297" /></p>
<p>DotCMS是一个<span style="font-weight: bold;">开源</span>的 企业级内容管理系统，它融入了电子商 务、个性化设置、客户关系管理工具等功能，它可以方便的建立基于各种关系的数据结构和数据库，它可以使用模板快速创建页面，并且提供了一个强大的所见即所 得(WYSIWYG)编辑器。用户可以使用加载外部模块的功能快速的建立Ajax应用、搜索、MP3播放器、幻灯片和相册等功能。</p>
<p><a href="http://dotcms.org/" target="_blank">DotCMS</a><a href="http://dotcms.org/" target="_blank">官方网站</a> <a href="http://www.javaeye.com/wiki/topic/277794" target="_blank">中文安装教程</a></p>
<h3>3. Magnolia</h3>
<p style="text-align: center;"><img class="size-full wp-image-8578 aligncenter" src="http://oncoding.net/uploads/allimg/090503/12515I964-2.png" alt="magnolia" width="435" height="386" /></p>
<p>Magnolia是一个老牌的java内容管理系统，目前已经发布了第四版。它的独特之处在于可以定制内容模型，以返回数组形式来搞定各种不确定的 功能。它遵循W3C标准并且在搜索引擎优化上有许多优势。同时它支持java内容仓库( java content repositories , JCR) 的API。</p>
<p><a href="http://www.magnolia-cms.com/home.html" target="_blank">Magnolia官方网站</a></p>
<h3>4. OpenCms</h3>
<p><img class="alignleft size-full wp-image-8593" src="http://oncoding.net/uploads/allimg/090503/12515H0X-3.gif" alt="app-opencms-small" width="500" height="335" /></p>
<p>它提供了一套建立和维护网站的方便的工具。在内容建设方面，它拥有一个易于使用的界面和所见即所得编辑器，在网页生成上它使用了一个先进的页面模板。</p>
<p><a href="http://www.opencms.org/opencms/en/index.html" target="_blank">OpenCMS官方网站</a> <a href="http://www.opencms.cn/" target="_blank">中文网站<br />
</a></p>
<h3>6. AtLeap</h3>
<p style="text-align: center;"><img class="size-full wp-image-8586 aligncenter" src="http://oncoding.net/uploads/allimg/090503/12515G019-4.gif" alt="atleap" width="424" height="302" /></p>
<p>Blandware AtLeap是一个多语种的免费<a class="bodytag" href="http://www.yeeyan.com/articles/tag/Java" target="_blank"><em>Java</em></a>内容管理系统，它包含了全文搜索引擎，可以算是一个能让你方便的编写应用的网站框架。</p>
<p><a href="https://atleap.dev.java.net/" target="_blank">Atleap官方网站</a></p>
<h3>7. Fedora</h3>
<p><a href="http://oncoding.net/uploads/090503/1_122934_1.jpg" target="_blank"><img style="width: 424px; height: 235px;" src="http://oncoding.net/uploads/090503/1_122934_1.jpg" border="0" alt="" /></a></p>
<p>Fedora 是“Flexible Extensible Digital Object Repository Architecture”的缩写，并不是Linux发行版Fedora，是一个数字资源管理系统，它可以创建很多类型的数字图书馆、资料库、档案馆系统 等。</p>
<p><a href="http://www.fedora-commons.org/" target="_blank">Fedora官方网站</a></p>
<h3>8. Apache Lenya</h3>
<p style="text-align: center;"><img class="size-full wp-image-8588 aligncenter" src="http://oncoding.net/uploads/allimg/090503/12515L156-5.gif" alt="apache-lenya" width="390" height="303" /></p>
<p>这是一个<span style="font-weight: bold;">开源</span>的 Java/XML 内容管理系统，提供了版本控制、多站点管理、调度、搜索、所见即所得编辑以及工作流程等功能。Apache Lyenya使用基于模块的Cocoom开源程序框架。</p>
<p><a href="http://lenya.apache.org/" target="_blank">Apache Lyenya官方网站</a></p>
<h3>9. OpenEdit</h3>
<p style="text-align: center;"><img class="size-full wp-image-8590 aligncenter" src="http://oncoding.net/uploads/allimg/090503/12515MS6-6.jpg" alt="openedit" width="420" height="276" /></p>
<p>OpenEdit是一个<span style="font-weight: bold;">开源</span>的内容管理系统，它旨在建设基于在线数字资产的多媒体网站。它提供在线编辑，动态布局，拼写检查，用户管理器，文件管理器，版本控制和通知工具。同时包含企业级的插件，如电子商务，内容管理，博客，活动日程表，社交网络工具等。</p>
<p><a href="http://www.openedit.org/" target="_blank">OpenEdit官方网站</a></p>
<h3>10.  Contelligent</h3>
<p>这个基于<a class="bodytag" href="http://www.yeeyan.com/articles/tag/Java" target="_blank"><em>Java</em></a>的<span style="font-weight: bold;">开源</span>解决方案有助于创建和管理个性化网站。它完全遵循J2EE，具有先进的模式，可以方便的添加第三方应用。</p>
<p><a href="http://www.contelligent.com/" target="_blank">Contelligent官方网站</a></p>
<p><a href="http://blog.taragana.com/index.php/archive/top-10-java-content-management-software/" target="_blank">原文：Taragana</a></p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2009. |
<a href="http://www.iwanna.cn/archives/2009/05/03/931/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2009/05/03/931/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2009/05/03/931/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2009/05/03/931/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2009/05/03/931/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2009/05/03/931/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java过滤特殊字符的正则表达式</title>
		<link>http://www.iwanna.cn/archives/2009/04/17/476/</link>
		<comments>http://www.iwanna.cn/archives/2009/04/17/476/#comments</comments>
		<pubDate>Fri, 17 Apr 2009 02:01:59 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[RegEx]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=476</guid>
		<description><![CDATA[Java正则表达式学习： 因为正则表达式是一个很庞杂的体系，此例仅举些入门的概念，更多的请参阅相关书籍及自行摸索。 \\ 反斜杠 \t 间隔 (&#8216;\u0009&#8242;) \n 换行 (&#8216;\u000A&#8217;) \r 回车 (&#8216;\u000D&#8217;) \d 数字 等价于[0-9] \D 非数字 等价于[^0-9] \s 空白符号 [\t\n\x0B\f\r] \S 非空白符号 [^\t\n\x0B\f\r] \w 单独字符 [a-zA-Z_0-9] \W 非单独字符 [^a-zA-Z_0-9] \f 换页符 \e Escape \b 一个单词的边界 \B 一个非单词的边界 \G 前一个匹配的结束 ^为限制开头 ^java     条件限制为以Java为开头字符 $为限制结尾 java$     条件限制为以java为结尾字符 . 条件限制除\n以外任意一个单独字符 java..     条件限制为java后除换行外任意两个字符 加入特定限制条件「[]」 [a-z]     条件限制在小写a to [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Java正则表达式学习：</strong><br />
因为正则表达式是一个很庞杂的体系，此例仅举些入门的概念，更多的请参阅相关书籍及自行摸索。</p>
<p>\\ 反斜杠<br />
\t 间隔 (&#8216;\u0009&#8242;)<br />
\n 换行 (&#8216;\u000A&#8217;)<br />
\r 回车 (&#8216;\u000D&#8217;)<br />
\d 数字 等价于[0-9]<br />
\D 非数字 等价于[^0-9]<br />
\s 空白符号 [\t\n\x0B\f\r]<br />
\S 非空白符号 [^\t\n\x0B\f\r]<br />
\w 单独字符 [a-zA-Z_0-9]<br />
\W 非单独字符 [^a-zA-Z_0-9]<br />
\f 换页符<br />
<span id="more-476"></span>\e Escape<br />
\b 一个单词的边界<br />
\B 一个非单词的边界<br />
\G 前一个匹配的结束</p>
<p>^为限制开头<br />
^<a href="http://www.iwanna.cn/tags/java/" class="st_tag internal_tag" rel="tag" title="标签 Java 下的日志">java</a>     条件限制为以Java为开头字符<br />
$为限制结尾<br />
java$     条件限制为以java为结尾字符<br />
. 条件限制除\n以外任意一个单独字符<br />
java..     条件限制为java后除换行外任意两个字符</p>
<p>加入特定限制条件「[]」<br />
[a-z]     条件限制在小写a to z范围中一个字符<br />
[A-Z]     条件限制在大写A to Z范围中一个字符<br />
[a-zA-Z] 条件限制在小写a to z或大写A to Z范围中一个字符<br />
[0-9]     条件限制在小写0 to 9范围中一个字符<br />
[0-9a-z] 条件限制在小写0 to 9或a to z范围中一个字符<br />
[0-9[a-z]] 条件限制在小写0 to 9或a to z范围中一个字符(交集)</p>
<p>[]中加入^后加再次限制条件「[^]」<br />
[^a-z]     条件限制在非小写a to z范围中一个字符<br />
[^A-Z]     条件限制在非大写A to Z范围中一个字符<br />
[^a-zA-Z] 条件限制在非小写a to z或大写A to Z范围中一个字符<br />
[^0-9]     条件限制在非小写0 to 9范围中一个字符<br />
[^0-9a-z] 条件限制在非小写0 to 9或a to z范围中一个字符<br />
[^0-9[a-z]] 条件限制在非小写0 to 9或a to z范围中一个字符(交集)</p>
<p>在限制条件为特定字符出现0次以上时，可以使用「*」<br />
J*     0个以上J<br />
.*     0个以上任意字符<br />
J.*D     J与D之间0个以上任意字符</p>
<p>在限制条件为特定字符出现1次以上时，可以使用「+」<br />
J+     1个以上J<br />
.+     1个以上任意字符<br />
J.+D     J与D之间1个以上任意字符</p>
<p>在限制条件为特定字符出现有0或1次以上时，可以使用「?」<br />
JA?     J或者JA出现</p>
<p>限制为连续出现指定次数字符「{a}」<br />
J{2}     JJ<br />
J{3}     JJJ<br />
文字a个以上，并且「{a,}」<br />
J{3,}     JJJ,JJJJ,JJJJJ,???(3次以上J并存)<br />
文字个以上，b个以下「{a,b}」<br />
J{3,5}     JJJ或JJJJ或JJJJJ<br />
两者取一「|」<br />
J|A     J或A<br />
Java|Hello     Java或Hello</p>
<p>「()」中规定一个组合类型<br />
比如，我查询&lt;a href=\&#8221;index.html\&#8221;&gt;index&lt;/a&gt;中&lt;a href&gt;&lt;/a&gt;间的数据，可写作&lt;a.*href=\&#8221;.*\&#8221;&gt;(.+?)&lt;/a&gt;</p>
<p>在使用Pattern.compile函数时，可以加入控制正则表达式的匹配行为的参数：<br />
Pattern Pattern.compile(String <a href="http://www.iwanna.cn/tags/regex/" class="st_tag internal_tag" rel="tag" title="标签 RegEx 下的日志">regex</a>, int flag)</p>
<p>flag的取值范围如下：<br />
Pattern.CANON_EQ     当且仅当两个字符的&#8221;正规分解(canonical decomposition)&#8221;都完全相同的情况下，才认定匹配。比如用了这个标志之后，表达式&#8221;a\u030A&#8221;会匹配&#8221;?&#8221;。默认情况下，不考虑&#8221;规 范相等性(canonical equivalence)&#8221;。<br />
Pattern.CASE_INSENSITIVE(?i)     默认情况下，大小写不明感的匹配只适用于US-ASCII字符集。这个标志能让表达式忽略大小写进行匹配。要想对Unicode字符进行大小不明感的匹 配，只要将UNICODE_CASE与这个标志合起来就行了。<br />
Pattern.COMMENTS(?x)     在这种模式下，匹配时会忽略(正则表达式里的)空格字符(译者注：不是指表达式里的&#8221;\\s&#8221;，而是指表达式里的空格，tab，回车之类)。注释从#开始，一直到这行结束。可以通过嵌入式的标志来启用Unix行模式。<br />
Pattern.DOTALL(?s)     在这种模式下，表达式&#8217;.'可以匹配任意字符，包括表示一行的结束符。默认情况下，表达式&#8217;.'不匹配行的结束符。<br />
Pattern.MULTILINE<br />
(?m)     在这种模式下，&#8217;^'和&#8217;$'分别匹配一行的开始和结束。此外，&#8217;^'仍然匹配字符串的开始，&#8217;$'也匹配字符串的结束。默认情况下，这两个表达式仅仅匹配字符串的开始和结束。<br />
Pattern.UNICODE_CASE<br />
(?u)     在这个模式下，如果你还启用了CASE_INSENSITIVE标志，那么它会对Unicode字符进行大小写不明感的匹配。默认情况下，大小写不敏感的匹配只适用于US-ASCII字符集。<br />
Pattern.UNIX_LINES(?d)     在这个模式下，只有&#8217;\n&#8217;才被认作一行的中止，并且与&#8217;.'，&#8217;^'，以及&#8217;$'进行匹配。</p>
<p>抛开空泛的概念，下面写出几个简单的Java正则用例：</p>
<p>◆比如，在字符串包含验证时</p>
<p>//查找以Java开头,任意结尾的字符串<br />
Pattern pattern = Pattern.compile(&#8220;^Java.*&#8221;);<br />
Matcher matcher = pattern.matcher(&#8220;Java不是人&#8221;);<br />
boolean b= matcher.matches();<br />
//当条件满足时，将返回true，否则返回false<br />
System.out.println(b);</p>
<p>◆以多条件分割字符串时<br />
Pattern pattern = Pattern.compile(&#8220;[, |]+&#8221;);<br />
String[] strs = pattern.split(&#8220;Java Hello World Java,Hello,,World|Sun&#8221;);<br />
for (int i=0;i&lt;strs.length;i++) {<br />
System.out.println(strs[i]);<br />
}</p>
<p>◆文字替换（首次出现字符）<br />
Pattern pattern = Pattern.compile(&#8220;正则表达式&#8221;);<br />
Matcher matcher = pattern.matcher(&#8220;正则表达式 Hello World,正则表达式 Hello World&#8221;);<br />
//替换第一个符合正则的数据<br />
System.out.println(matcher.replaceFirst(&#8220;Java&#8221;));</p>
<p>◆文字替换（全部）<br />
Pattern pattern = Pattern.compile(&#8220;正则表达式&#8221;);<br />
Matcher matcher = pattern.matcher(&#8220;正则表达式 Hello World,正则表达式 Hello World&#8221;);<br />
//替换第一个符合正则的数据<br />
System.out.println(matcher.replaceAll(&#8220;Java&#8221;));</p>
<p>◆文字替换（置换字符）<br />
Pattern pattern = Pattern.compile(&#8220;正则表达式&#8221;);<br />
Matcher matcher = pattern.matcher(&#8220;正则表达式 Hello World,正则表达式 Hello World &#8220;);<br />
StringBuffer sbr = new StringBuffer();<br />
while (matcher.find()) {<br />
matcher.appendReplacement(sbr, &#8220;Java&#8221;);<br />
}<br />
matcher.appendTail(sbr);<br />
System.out.println(sbr.toString());</p>
<p>◆验证是否为邮箱地址</p>
<p>String str=&#8221;ceponline@yahoo.com.cn&#8221;;<br />
Pattern pattern = Pattern.compile(&#8220;[\\w\\.\\-]+@([\\w\\-]+\\.)+[\\w\\-]+&#8221;,Pattern.CASE_INSENSITIVE);<br />
Matcher matcher = pattern.matcher(str);<br />
System.out.println(matcher.matches());</p>
<p>◆去除html标记<br />
Pattern pattern = Pattern.compile(&#8220;&lt;.+?&gt;&#8221;, Pattern.DOTALL);<br />
Matcher matcher = pattern.matcher(&#8220;&lt;a href=\&#8221;index.html\&#8221;&gt;主页&lt;/a&gt;&#8221;);<br />
String string = matcher.replaceAll(&#8220;&#8221;);<br />
System.out.println(string);</p>
<p>◆查找html中对应条件字符串<br />
Pattern pattern = Pattern.compile(&#8220;href=\&#8221;(.+?)\&#8221;");<br />
Matcher matcher = pattern.matcher(&#8220;&lt;a href=\&#8221;index.html\&#8221;&gt;主页&lt;/a&gt;&#8221;);<br />
if(matcher.find())<br />
System.out.println(matcher.group(1));<br />
}</p>
<p>◆截取http://地址<br />
//截取url<br />
Pattern pattern = Pattern.compile(&#8220;(http://|https://){1}[\\w\\.\\-/:]+&#8221;);<br />
Matcher matcher = pattern.matcher(&#8220;dsdsds&lt;http://dsds//gfgffdfd&gt;fdf&#8221;);<br />
StringBuffer buffer = new StringBuffer();<br />
while(matcher.find()){<br />
buffer.append(matcher.group());<br />
buffer.append(&#8220;\r\n&#8221;);<br />
System.out.println(buffer.toString());<br />
}</p>
<p>◆替换指定{}中文字</p>
<p>String str = &#8220;Java目前的发展史是由{0}年-{1}年&#8221;;<br />
String[][] object={new String[]{&#8220;\\{0\\}&#8221;,&#8221;1995&#8243;},new String[]{&#8220;\\{1\\}&#8221;,&#8221;2007&#8243;}};<br />
System.out.println(replace(str,object));</p>
<p>public static String replace(final String sourceString,Object[] object) {<br />
String temp=sourceString;<br />
for(int i=0;i&lt;object.length;i++){<br />
String[] result=(String[])object[i];<br />
Pattern    pattern = Pattern.compile(result[0]);<br />
Matcher matcher = pattern.matcher(temp);<br />
temp=matcher.replaceAll(result[1]);<br />
}<br />
return temp;<br />
}</p>
<p>◆以正则条件查询指定目录下文件</p>
<p>//用于缓存文件列表<br />
private ArrayList files = new ArrayList();<br />
//用于承载文件路径<br />
private String _path;<br />
//用于承载未合并的正则公式<br />
private String _regexp;</p>
<p>class MyFileFilter implements FileFilter {</p>
<p>/**<br />
* 匹配文件名称<br />
*/<br />
public boolean accept(File file) {<br />
try {<br />
Pattern pattern = Pattern.compile(_regexp);<br />
Matcher match = pattern.matcher(file.getName());<br />
return match.matches();<br />
} catch (Exception e) {<br />
return true;<br />
}<br />
}<br />
}</p>
<p>/**<br />
* 解析输入流<br />
* @param inputs<br />
*/<br />
FilesAnalyze (String path,String regexp){<br />
getFileName(path,regexp);<br />
}</p>
<p>/**<br />
* 分析文件名并加入files<br />
* @param input<br />
*/<br />
private void getFileName(String path,String regexp) {<br />
//目录<br />
_path=path;<br />
_regexp=regexp;<br />
File directory = new File(_path);<br />
File[] filesFile = directory.listFiles(new MyFileFilter());<br />
if (filesFile == null) return;<br />
for (int j = 0; j &lt; filesFile.length; j++) {<br />
files.add(filesFile[j]);<br />
}<br />
return;<br />
}</p>
<p>/**<br />
* 显示输出信息<br />
* @param out<br />
*/<br />
public void print (PrintStream out) {<br />
Iterator elements = files.iterator();<br />
while (elements.hasNext()) {<br />
File file=(File) elements.next();<br />
out.println(file.getPath());<br />
}<br />
}</p>
<p>public static void output(String path,String regexp) {</p>
<p>FilesAnalyze fileGroup1 = new FilesAnalyze(path,regexp);<br />
fileGroup1.print(System.out);<br />
}</p>
<p>public static void main (String[] args) {<br />
output(&#8220;C:\\&#8221;,&#8221;[A-z|.]*&#8221;);<br />
}</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2009. |
<a href="http://www.iwanna.cn/archives/2009/04/17/476/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2009/04/17/476/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2009/04/17/476/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2009/04/17/476/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2009/04/17/476/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2009/04/17/476/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>设计模式之单例模式</title>
		<link>http://www.iwanna.cn/archives/2009/04/02/149/</link>
		<comments>http://www.iwanna.cn/archives/2009/04/02/149/#comments</comments>
		<pubDate>Thu, 02 Apr 2009 05:00:34 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Patten]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[我想想想]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=149</guid>
		<description><![CDATA[1 单例模式的日常应用 我们在浏览BBS、SNS网站的时候，常常会看到“当前在线人数”这样的一项内容。对于 这样的一项功能，我们通常的做法是把当前的在线人数存放到一个内存、文件或者数据库中，每次用户登录的时候，就会马上从内存、文件或者数据库中取出，在其基础上加1后，作为当前的在线人数进行显示，然后再把它保存回内存、文件或者数据库里，这样后续登录的用户看到的就是更新后的当前在线人数；同样的道理，当用户退出后，当前在线人数进行减1的工作。所以，对于这样的一个需求，我们按照面向对象的设计思想，可以把它抽象为“在线计数器”这样一个对象，具体实现如下： Java代码： //在线人数计数器 class OnlineCounter { //在线人数 private int onlineCount = 0; //构造函数 public OnlineCounter(){ //从文件或者数据库读取数据,假如读出来的数据是100 this.onlineCount = 100; } //在用户登录后，在线人数加1 public void incCount(){ this.onlineCount++; } //在用户退出后，在线人数减1 public void decCount(){ this.onlineCount&#8211;; } //保存在线人数 public void saveCount(){ } //获取在线人数 public int getCount(){ return onlineCount; } //测试函数 public static void main(String[] args) { try{ [...]]]></description>
			<content:encoded><![CDATA[<p>1         单例模式的日常应用</p>
<p>我们在浏览BBS、SNS网站的时候，常常会看到“当前在线人数”这样的一项内容。对于</p>
<p>这样的一项功能，我们通常的做法是把当前的在线人数存放到一个内存、文件或者数据库中，每次用户登录的时候，就会马上从内存、文件或者数据库中取出，在其基础上加1后，作为当前的在线人数进行显示，然后再把它保存回内存、文件或者数据库里，这样后续登录的用户看到的就是更新后的当前在线人数；同样的道理，当用户退出后，当前在线人数进行减1的工作。所以，对于这样的一个需求，我们按照面向对象的设计思想，可以把它抽象为“在线计数器”这样一个对象，具体实现如下：</p>
<p><span id="more-149"></span></p>
<p>Java代码：</p>
<p>//在线人数计数器</p>
<p>class OnlineCounter {</p>
<p>//在线人数</p>
<p>private int onlineCount = 0;</p>
<p>//构造函数</p>
<p>public OnlineCounter(){</p>
<p>//从文件或者数据库读取数据,假如读出来的数据是100</p>
<p>this.onlineCount = 100;</p>
<p>}</p>
<p>//在用户登录后，在线人数加1</p>
<p>public void incCount(){</p>
<p>this.onlineCount++;</p>
<p>}</p>
<p>//在用户退出后，在线人数减1</p>
<p>public void decCount(){</p>
<p>this.onlineCount&#8211;;</p>
<p>}</p>
<p>//保存在线人数</p>
<p>public void saveCount(){</p>
<p>}</p>
<p>//获取在线人数</p>
<p>public int getCount(){</p>
<p>return onlineCount;</p>
<p>}</p>
<p>//测试函数</p>
<p>public static void main(String[] args) {</p>
<p>try{</p>
<p>OnlineCounter onlineCounter = new OnlineCounter();</p>
<p>System.out.println(&#8220;在线人数：&#8221; +onlineCounter.getCount());</p>
<p>onlineCounter.incCount();</p>
<p>System.out.println(&#8220;在线人数：&#8221; + onlineCounter.getCount());</p>
<p>onlineCounter.decCount();</p>
<p>System.out.println(&#8220;在线人数：&#8221; + onlineCounter.getCount());</p>
<p>}catch(Exception err){</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>.Net代码：</p>
<p>//在线人数计数器</p>
<p>class OnlineCounter{</p>
<p>//在线人数</p>
<p>private int onlineCount = 0;</p>
<p>//构造函数</p>
<p>public OnlineCounter(){</p>
<p>//从文件或者数据库读取数据,假如读出来的数据是100</p>
<p>this.onlineCount = 100;</p>
<p>}</p>
<p>//在用户登录后，在线人数加1</p>
<p>public void incCount(){</p>
<p>this.onlineCount++;</p>
<p>}</p>
<p>//在用户退出后，在线人数减1</p>
<p>public void decCount(){</p>
<p>this.onlineCount&#8211;;</p>
<p>}</p>
<p>//保存在线人数</p>
<p>public void saveCount(){</p>
<p>return onlineCount;</p>
<p>}</p>
<p>//获取在线人数</p>
<p>public int getCount(){</p>
<p>return onlineCount;</p>
<p>}</p>
<p>//测试函数</p>
<p>public static void Main(string[] args) {</p>
<p>OnlineCounter onlineCounter = new OnlineCounter();</p>
<p>Console.WriteLine(&#8220;在线人数：&#8221; + onlineCounter.getCount());</p>
<p>onlineCounter.incCount();</p>
<p>Console.WriteLine(&#8220;在线人数：&#8221; + onlineCounter.getCount());</p>
<p>onlineCounter.decCount();</p>
<p>Console.WriteLine(&#8220;在线人数：&#8221; + onlineCounter.getCount());</p>
<p>}</p>
<p>}</p>
<p>Php代码：</p>
<p>//在线人数计数器</p>
<p>class OnlineCounter {</p>
<p>//在线人数</p>
<p>private $onlineCount = 0;</p>
<p>//构造函数</p>
<p>public function __construct(){</p>
<p>//从文件或者数据库读取数据,假如读出来的数据是100</p>
<p>$this-&gt;onlineCount = 100;</p>
<p>}</p>
<p>//在用户登录后，在线人数加1</p>
<p>public function incCount(){</p>
<p>$this-&gt;onlineCount++;</p>
<p>}</p>
<p>//在用户退出后，在线人数减1</p>
<p>public function decCount(){</p>
<p>$this-&gt;onlineCount&#8211;;</p>
<p>}</p>
<p>//保存在线人数</p>
<p>public function saveCount(){</p>
<p>}</p>
<p>//获取在线人数</p>
<p>public function getCount(){</p>
<p>return $this-&gt;onlineCount;</p>
<p>}</p>
<p>//测试函数</p>
<p>public static function execute() {</p>
<p>$onlineCounter = new OnlineCounter();</p>
<p>echo &#8220;在线人数：&#8221; . $onlineCounter-&gt;getCount();</p>
<p>$onlineCounter-&gt;incCount();</p>
<p>echo &#8220;在线人数：&#8221; . $onlineCounter-&gt;getCount();</p>
<p>$onlineCounter-&gt;decCount();</p>
<p>echo &#8220;在线人数：&#8221; . $onlineCounter-&gt;getCount();</p>
<p>}</p>
<p>}</p>
<p>OnlineCounter::execute();</p>
<p>?&gt;</p>
<p>运行结果如下：</p>
<p>在线人数：100</p>
<p>在线人数：101</p>
<p>在线人数：100</p>
<p>网站代码中凡是用到计数器的地方，只要new一个计数器对象，然后就可以获取、保存、增加或者减少在线人数的数量。不过，我们的代码实际的使用效果并不好。假如有多个用户同时登录,那么在这个时刻，通过计数器取到的在线人数是相同的，于是他们使用各自的计数器加1后存入文件或者数据库。这样操作后续登陆的用户得到的在线人数，与实际的在线人数并不一致。所以，把这个计数器设计为一个全局对象，所有人都共用同一份数据，就可以避免类似的问题，这就是我们所说的单例模式的其中的一种应用。<br />
2         什么是单例模式</p>
<p>单例模式能够保证一个类仅有唯一的实例，并提供一个全局访问点。</p>
<p>我们是不是可以通过一个全局变量来实现单例模式的要求呢？我们只要仔细地想想看，全局变量确实可以提供一个全局访问点，但是它不能防止别人实例化多个对象。通过外部程序来控制的对象的产生的个数，势必会系统的增加管理成本，增大模块之间的耦合度。所以，最好的解决办法就是让类自己负责保存它的唯一实例，并且让这个类保证不会产生第二个实例，同时提供一个让外部对象访问该实例的方法。自己的事情自己办，而不是由别人代办，这非常符合面向对象的封装原则。</p>
<p>按照以上的思路，我们可以这样来设计单例类：</p>
<p>Java代码:</p>
<p>class Singleton {</p>
<p>// 私有的静态对象</p>
<p>private static Singleton instance = null;</p>
<p>//私有的构造方法</p>
<p>private Singleton (){</p>
<p>}</p>
<p>// 公开的静态工厂方法,返回此类的唯一实例</p>
<p>public static Singleton getInstance(){</p>
<p>if(instance == null){</p>
<p>instance = new Singleton();</p>
<p>}</p>
<p>return instance;</p>
<p>}</p>
<p>}</p>
<p>.Net代码：</p>
<p>class Singleton{</p>
<p>// 私有的静态对象</p>
<p>private static Singleton instance = null;</p>
<p>//私有的构造方法</p>
<p>private Singleton(){</p>
<p>}</p>
<p>//公开的静态工厂方法,返回此类的唯一实例</p>
<p>public static Singleton getInstance(){</p>
<p>if (instance == null){</p>
<p>instance = new Singleton();</p>
<p>}</p>
<p>return instance;</p>
<p>}</p>
<p>}</p>
<p>Php代码：</p>
<p>class Singleton {</p>
<p>// 私有的静态对象</p>
<p>private static $instance = null;</p>
<p>//私有的构造方法</p>
<p>private function __construct(){</p>
<p>}</p>
<p>// 公开的静态工厂方法,返回此类的唯一实例</p>
<p>public static function getInstance(){</p>
<p>if(self::$instance == null){</p>
<p>self::$instance = new Singleton();</p>
<p>}</p>
<p>return self::$instance;</p>
<p>}</p>
<p>}</p>
<p>?&gt;</p>
<p>Singleton类含有一个instance的私有静态变量,用来保存该类唯一的实例对象，它对于外部对象是不可见的，只能通过getInstance方法才能获得。</p>
<p>Singleton类的构造器是private私有的，外部对象无法通过它的构造器生成实例，也就是说外部程序试图通过new操作符来创建实例是行不通的，因此，getInstance方法成为获得Singleton类实例的唯一途径。</p>
<p>getInstance方法的设计非常简单，它首先检测instance变量是否已经初始化，如果没有被初始化，就创建一个实例保存到instance变量，最后返回这个实例；如果这个实例已经被初始化，那么就直接返回这个实例。</p>
<p>getInstance方法的设计非常简单，它首先检测instance变量是否已经初始化，如果没有被初始化，就创建一个实例保存到instance变量，最后返回这个实例；如果这个实例已经被初始化，那么就直接返回这个实例。</p>
<p>单例模式的类图</p>
<p>单例模式主要有3个特点，：</p>
<p>1、单例类确保自己只有一个实例。</p>
<p>2、单例类必须自己创建自己的实例。</p>
<p>3、单例类必须为其他对象提供唯一的实例。<br />
3         安全的单例模式：双重检查锁定机制</p>
<p>我们虽然实现了单例模式，但是目前的解决办法并不安全，依然存在着一定的缺陷：</p>
<p>class Singleton {</p>
<p>private static Singleton instance = null;</p>
<p>private Singleton (){</p>
<p>}</p>
<p>public static Singleton getInstance(){</p>
<p>if(instance == null){</p>
<p>instance = new Singleton();</p>
<p>}</p>
<p>return instance;</p>
<p>}</p>
<p>}</p>
<p>这段代码意图通过检查if (instance == null)这个条件，来保证只创建一个Singleton实例。事实上，它运行在单线程环境中，得到的结果是正确的，没有问题，但是运行在多线程的环境中，它就会出现错误，可能有多个Singleton实例被创建出来。</p>
<p>我们分析一下，在多线程环境中，可能会出现这样的情形：线程A 和线程B几乎同时到达if (instance == null)语句，假设线程A 比线程B 早一点点，那么：</p>
<p>（1）A 会首先进入if (instance == null)块的内部，并开始执行new Singleton () 语句。此时，instance变量仍然是null，直到线程A 的new Singleton () 语句返回，并给instance变量赋值为止。</p>
<p>（2） 但是，此时的线程B 并不会在if (instance == null)语句的外面等待，因为此时(instance == null)是成立的，它会马上进入if (instance == null)语句块的内部。这样，线程B 会不可避免地执行instance=new Singleton()语句，从而创建出第二个实例来。</p>
<p>（3）线程A 的instance=new Singleton()语句执行完毕后，instance变量得到了真实的对象引用，(instance == null)不再为真。所以，后来的线程就不会再进入if (instance == null) 语句块的内部了。</p>
<p>（4）线程B 的instance=new Singleton()语句也执行完毕后，instance变量的值被覆盖。但是第一个instance对象被线程A 引用的事实已经无法改变了。这时候的线程A和B各自拥有一个独立的Singleton对象。</p>
<p>为了实现线程安全，我们对代码进行了一定的改造：</p>
<p>Java代码：</p>
<p>class Singleton{</p>
<p>private static Singleton instance = null;</p>
<p>private Singleton() {</p>
<p>}</p>
<p>public static Singleton getInstance(){</p>
<p>//位置1，第1次检查instance</p>
<p>if (instance == null)</p>
<p>{</p>
<p>//位置2，某一时刻可能有n个线程到达</p>
<p>synchronized (this)</p>
<p>{</p>
<p>//位置3，任何时间只能有1个线程到达</p>
<p>if (instance == null) //位置4，第2次检查instance</p>
<p>{</p>
<p>instance = new Singleton();</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>return instance;</p>
<p>}</p>
<p>}</p>
<p>.Net代码：</p>
<p>class Singleton {</p>
<p>private static Singleton instance = null;</p>
<p>private static readonly object syncObj = new object();</p>
<p>private Singleton (){</p>
<p>}</p>
<p>public static Singleton getInstance(){</p>
<p>//位置1，第1次检查instance</p>
<p>if( instance == null ){</p>
<p>//位置2，某一时刻可能有n个线程到达</p>
<p>lock(syncObj)</p>
<p>{</p>
<p>//位置3，任何时间只能有1个线程到达</p>
<p>if (instance == null) //位置4，第2次检查instance</p>
<p>{</p>
<p>instance = new Singleton();</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>return instance;</p>
<p>}</p>
<p>}</p>
<p>我们通过引入了Java的synchronized或者.Net的lock同步化限制，各个线程到达临界区时，就会按照线性方式逐个执行。</p>
<p>我们再来分析一下：</p>
<p>（1）在多线程环境中，线程A 和B同时或几乎同时到达位置1。</p>
<p>（2）假设线程A 会首先到达位置2，并进入synchronized(this) 到达位置3。这时，由于synchronized(this) 的同步化限制，线程B 无法到达位置3，而只能在位置2 等候。</p>
<p>（3）线程A 执行instance = new Singleton()语句，instance变量得到赋值，此时，线程B 还只能继续在位置2 等候。</p>
<p>（4）线程A 退出synchronized(this) 块，并返回instance对象。</p>
<p>（5）线程B 进入synchronized(this)块，到达位置3，进而到达位置4。由于instance变量已经不是null 了，因此线程B 退出synchronized(this)，并返回instance，这时候的instance只有一个。</p>
<p>我们通过两次检查instance是否被实例化来解决线程安全问题，这种处理方式称为双重检查锁定机制（Double-checked locking）。还有另外一种解决线程安全的方法，就是把getInstance方法整体作为同步区，比如声明为public static synchronized Singleton getInstance()，这种方式由于锁定的区域过大，特殊情况下会造成系统性能的下降，成为系统的性能瓶颈。</p>
<p>双重检查锁定机制不仅解决了线程安全问题，而且把性能也处理得很不错，看起来非常完美。不幸的是我们应该注意不要在java中使用双重检查锁定机制，由于Java编译器和 JIT 的优化的原因，系统无法保证我们期望的执行次序。虽然Java语法中的volatile修饰符可以强制屏蔽编译器和 JIT 的优化工作，但它是一种非常脆弱的同步机制，比较难以控制，所以建议尽量减少使用。我们后面还提供了其它的一种实现方式。<br />
4         单例模式的实现方式：懒汉单例类和饿汉单例类</p>
<p>单例模式的实现有多种方法，常见的就有懒汉式单例类和饿汉式单例类。我们前面介绍的实现方法就属于懒汉式单例类。</p>
<p>l         懒汉式单例类</p>
<p>对于懒汉模式，我们可以这样理解：该单例类非常懒，只有在自身需要的时候才会行动，从来不知道及早做好准备。它在需要对象的时候，才判断是否已有对象，如果没有就立即创建一个对象，然后返回，如果已有对象就不再创建，立即返回。</p>
<p>懒汉模式只在外部对象第一次请求实例的时候才去创建。</p>
<p>l         饿汉式单例</p>
<p>对于饿汉模式，我们可以这样理解：该单例类非常饿，迫切需要吃东西，所以它在类加载的时候就立即创建对象。</p>
<p>Java代码：</p>
<p>final class Singleton {</p>
<p>//私有的唯一实例成员,在类加载的时候就创建好了单例对象</p>
<p>private static final Singleton instance = new Singleton();</p>
<p>//私有的构造方法,避免外部创建类实例</p>
<p>private Singleton() {</p>
<p>}</p>
<p>//静态工厂方法,返回此类的唯一实例</p>
<p>public static Singleton getInstance() {</p>
<p>return instance;</p>
<p>}</p>
<p>}</p>
<p>.Net代码：</p>
<p>sealed class Singleton {</p>
<p>//私有的唯一实例成员,在类加载的时候就创建好了单例对象</p>
<p>private static readonly Singleton instance = new Singleton();</p>
<p>//私有的构造方法,避免外部创建类实例</p>
<p>private Singleton() {</p>
<p>}</p>
<p>//静态工厂方法,返回此类的唯一实例</p>
<p>public static Singleton getInstance() {</p>
<p>return instance;</p>
<p>}</p>
<p>}</p>
<p>使用Java中的final关键字和.Net中sealed关键字去修饰class，目的是阻止派生子类，而派生子类可能会导致实例不唯一。使用Java中的final关键字和.Net中readonly关键字去修饰变量，就意味着只能在类初始化时或者在构造器中分配该变量。</p>
<p>我们对比一下懒汉模式和饿汉模式的优缺点：</p>
<p>懒汉模式，它的特点是运行时获得对象的速度比较慢，但加载类的时候比较快。它在整个应用的生命周期只有一部分时间在占用资源。</p>
<p>饿汉模式，它的特点是加载类的时候比较慢，但运行时获得对象的速度比较快。它从加载到应用结束会一直占用资源。</p>
<p>这两种模式对于初始化较快，占用资源少的对象来说，没有多大的性能差异，但是对于初始化慢，占用资源多的对象来说就会有比较明显的差别了。所以，对重量级对象应用饿汉模式，在类加载时需要较长时间，但运行时会有明显的时间效率的提升。对重量级对象应用懒汉模式，在类加载时很快，但至少第一次获得对象时需要等待很长时间。</p>
<p>从用户体验的角度来说，我们应该首选饿汉模式。我们愿意等待某个程序花较长的时间初始化，却不喜欢在程序运行时等待太久，给人一种反应迟钝的感觉，所以对于有重量级对象参与的单例模式，我们推荐使用饿汉模式。</p>
<p>而对于初始化较快的轻量级对象来说，选用哪种方法都可以。如果一个应用中使用了大量单例模式，我们就应该权衡两种方法了。轻量级对象的单例采用懒汉模式，减轻加载时的负担，缩短加载时间，提高加载效率；同时由于是轻量级对象，把这些对象的创建放在使用时进行，实际就是把创建单例对象所消耗的时间分摊到整个应用中去了，对于整个应用的运行效率没有太大影响。<br />
5         什么情况下使用单例模式</p>
<p>单例模式也是一种比较常见的设计模式，它到底能带给我们什么好处呢？其实无非是三个方面的作用：</p>
<p>第一、控制资源的使用，通过线程同步来控制资源的并发访问；</p>
<p>第二、控制实例产生的数量，达到节约资源的目的。</p>
<p>第三、作为通信媒介使用，也就是数据共享，它可以在不建立直接关联的条件下，让多个不相关的两个线程或者进程之间实现通信。</p>
<p>比如，数据库连接池的设计一般采用单例模式，数据库连接是一种数据库资源。软件系统中使用数据库连接池，主要是节省打开或者关闭数据库连接所引起的效率损耗，这种效率上的损耗还是非常昂贵的。当然，使用数据库连接池还有很多其它的好处，可以屏蔽不同数据数据库之间的差异，实现系统对数据库的低度耦合，也可以被多个系统同时使用，具有高可复用性，还能方便对数据库连接的管理等等。数据库连接池属于重量级资源，一个应用中只需要保留一份即可，既节省了资源又方便管理。所以数据库连接池采用单例模式进行设计会是一个非常好的选择。</p>
<p>在我们日常使用的在Windows中也有不少单例模式设计的组件，象常用的文件管理器。由于Windows操作系统是一个典型的多进程多线程系统，那么在创建或者删除某个文件的时候，就不可避免地出现多个进程或线程同时操作一个文件的现象。采用单例模式设计的文件管理器就可以完美的解决这个问题，所有的文件操作都必须通过唯一的实例进行，这样就不会产生混乱的现象。</p>
<p>再比如，每台计算机可以有若干个打印机，如果每一个进程或者线程都独立地使用打印机资源的话，那么我们打印出来的结果就有可能既包含这个打印任务的一部分，又包含另外一个打印任务的一部分。所以，大多数的操作系统最终为打印任务设计了一个单例模式的假脱机服务Printer Spooler，所有的打印任务都需要通过假脱机服务进行。</p>
<p>实际上，配置信息类、管理类、控制类、门面类、代理类通常被设计为单例类。像Java的Struts、Spring框架，.Net的Spring.Net框架，以及Php的Zend框架都大量使用了单例模式。</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2009. |
<a href="http://www.iwanna.cn/archives/2009/04/02/149/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2009/04/02/149/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2009/04/02/149/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2009/04/02/149/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2009/04/02/149/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2009/04/02/149/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

