﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-paulwong-随笔分类-Design Pattern</title><link>http://www.blogjava.net/paulwong/category/12268.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 26 Aug 2014 10:11:29 GMT</lastBuildDate><pubDate>Tue, 26 Aug 2014 10:11:29 GMT</pubDate><ttl>60</ttl><item><title>设计模式简释</title><link>http://www.blogjava.net/paulwong/archive/2014/08/26/417363.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Tue, 26 Aug 2014 09:34:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2014/08/26/417363.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/417363.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2014/08/26/417363.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/417363.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/417363.html</trackback:ping><description><![CDATA[策略模式：<br /><br />场景：又称警察模式，假设小明开快车，遇到警察，可能是好警察，只是口头警告一下，就让小明走了，也可能是强硬的警察，给小明开了罚单。但小明是不知道到底会遇到哪种警察，要到RUNTIME的时候才知道。<br /><br />不好的封装：将好警察的处罚行为封装为一个类A，将强硬警察的处罚行为封装为另一个类B，将判断如何处罚封装成一个类C，在这个类中判断类的类型，如果是A类，则执行A方法，如果是B类，则执行B方法。<br /><br />良好的封装：将警察的处罚行为统一为一个接口I-A的一个方法，类C的执行方法只传入接口I-A。<img src ="http://www.blogjava.net/paulwong/aggbug/417363.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2014-08-26 17:34 <a href="http://www.blogjava.net/paulwong/archive/2014/08/26/417363.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Design Pattern 资源</title><link>http://www.blogjava.net/paulwong/archive/2014/08/26/417332.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Tue, 26 Aug 2014 01:41:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2014/08/26/417332.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/417332.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2014/08/26/417332.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/417332.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/417332.html</trackback:ping><description><![CDATA[<a href="http://www.programcreek.com/category/design-patterns/page/5/" target="_blank">http://www.programcreek.com/category/design-patterns/page/5/</a><img src ="http://www.blogjava.net/paulwong/aggbug/417332.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2014-08-26 09:41 <a href="http://www.blogjava.net/paulwong/archive/2014/08/26/417332.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java设计模式：观察者</title><link>http://www.blogjava.net/paulwong/archive/2014/08/26/417322.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Tue, 26 Aug 2014 00:50:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2014/08/26/417322.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/417322.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2014/08/26/417322.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/417322.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/417322.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 简单来说，观察者模式=发布者+订阅者。下面是一个有关猎头的典型的例子。在下面这张图当中有两个角色：猎头和寻找工作的人。找工作的人向猎头订阅，告知自己希望得到一份工作，当有新的工作机会的时候，猎头就会把这个信息通知给曾经向他订阅过的人。Java代码Subject接口：1public&nbsp;interface&nbsp;Subject {2&nbsp;&nbsp;&nbsp;&nbsp;publi...&nbsp;&nbsp;<a href='http://www.blogjava.net/paulwong/archive/2014/08/26/417322.html'>阅读全文</a><img src ="http://www.blogjava.net/paulwong/aggbug/417322.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2014-08-26 08:50 <a href="http://www.blogjava.net/paulwong/archive/2014/08/26/417322.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Core J2EE Pattern</title><link>http://www.blogjava.net/paulwong/archive/2012/07/06/382402.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Fri, 06 Jul 2012 09:58:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2012/07/06/382402.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/382402.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2012/07/06/382402.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/382402.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/382402.html</trackback:ping><description><![CDATA[<img alt="" src="http://www.corej2eepatterns.com/images/CJP2Catalog.gif" height="798" width="648" /><br /><br /><img src ="http://www.blogjava.net/paulwong/aggbug/382402.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2012-07-06 17:58 <a href="http://www.blogjava.net/paulwong/archive/2012/07/06/382402.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一些软件设计的原则</title><link>http://www.blogjava.net/paulwong/archive/2011/04/27/349145.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Wed, 27 Apr 2011 15:51:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2011/04/27/349145.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/349145.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2011/04/27/349145.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/349145.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/349145.html</trackback:ping><description><![CDATA[本文为大家介绍软件设计中的一些原则，都是经过长期经验总结出来的知识，每一个程序员都应该了解，相信对大家在进行软件设计的过程中会有很大帮助。 <br />
<br />
<span style="color: blue"><strong>Don&#8217;t Repeat Yourself (DRY)</strong></span> <br />
DRY 是一个最简单的法则，也是最容易被理解的。但它也可能是最难被应用的（因为要做到这样，我们需要在泛型设计上做相当的努力，这并不是一件容易的事）。它意味着，当我们在两个或多个地方的时候发现一些相似的代码的时候，我们需要把他们的共性抽象出来形一个唯一的新方法，并且改变现有的地方的代码让他们以一些合适的参数调用这个新的方法。 <br />
参考：<a href="http://en.wikipedia.org/wiki/KISS_principle" target="_blank">http://en.wikipedia.org/wiki/KISS_principle</a> <br />
<br />
<span style="color: blue"><strong>Program to an interface, not an implementation</strong></span> <br />
这是设计模式中最根本的哲学，注重接口，而不是实现，依赖接口，而不是实现。接口是抽象是稳定的，实现则是多种多样的。以后面我们会面向对象的SOLID原则中会提到我们的依赖倒置原则，就是这个原则的的另一种样子。还有一条原则叫 Composition over inheritance（喜欢组合而不是继承），这两条是那23个经典设计模式中的设计原则。 <br />
<br />
<span style="color: blue"><strong>Command-Query Separation (CQS)&nbsp; &#8211; 命令-查询分离原则</strong></span> <br />
查询：当一个方法返回一个值来回应一个问题的时候，它就具有查询的性质； <br />
命令：当一个方法要改变对象的状态的时候，它就具有命令的性质； <br />
<br />
通常，一个方法可能是纯的Command模式或者是纯的Query模式，或者是两者的混合体。在设计接口时，如果可能，应该尽量使接口单一化，保证方法的行为严格的是命令或者是查询，这样查询方法不会改变对象的状态，没有副作用，而会改变对象的状态的方法不可能有返回值。也就是说：如果我们要问一个问题，那么就不应该影响到它的答案。实际应用，要视具体情况而定，语义的清晰性和使用的简单性之间需要权衡。将Command和Query功能合并入一个方法，方便了客户的使用，但是，降低了清晰性，而且，可能不便于基于断言的程序设计并且需要一个变量来保存查询结果。 <br />
<br />
在系统设计中，很多系统也是以这样原则设计的，查询的功能和命令功能的系统分离，这样有则于系统性能，也有利于系统的安全性。 <br />
<br />
参考：<a href="http://en.wikipedia.org/wiki/Command-query_separation" target="_blank">http://en.wikipedia.org/wiki/Command-query_separation</a> <br />
<br />
<span style="color: blue"><strong>You Ain&#8217;t Gonna Need It (YAGNI)</span></strong> <br />
这个原则简而言之为——只考虑和设计必须的功能，避免过度设计。只实现目前需要的功能，在以后您需要更多功能时，可以再进行添加。 <br />
<br />
如无必要，勿增复杂性。 <br />
软件开发先是一场沟通博弈。 <br />
<br />
以前本站有一篇关于<a href="http://coolshell.cn/articles/3005.html" target="_blank">过度重构的文章</a>，这个示例就是这个原则的反例。而，WebSphere的设计者就<a href="http://www.bbc.co.uk/news/business-11944966" target="_blank">表示过他过度设计了这个产品</a>。我们的程序员或是架构师在设计系统的时候，会考虑很多扩展性的东西，导致在架构与设计方面使用了大量折衷，最后导致项目失败。这是个令人感到讽刺的教训，因为本来希望尽可能延长项目的生命周期，结果反而缩短了生命周期。 <br />
<br />
参考：<a href="http://en.wikipedia.org/wiki/You_Ain%27t_Gonna_Need_It" target="_blank">http://en.wikipedia.org/wiki/You_Ain%27t_Gonna_Need_It</a> <br />
<br />
<span style="color: blue"><strong>Law of Demeter &#8211; 迪米特法则</strong></span> <br />
迪米特法则(Law of Demeter)，又称&#8220;最少知识原则&#8221;（Principle of Least Knowledge），其来源于1987年荷兰大学的一个叫做Demeter的项目。Craig Larman把Law of Demeter又称作&#8220;不要和陌生人说话&#8221;。在《程序员修炼之道》中讲LoD的那一章叫作&#8220;解耦合与迪米特法则&#8221;。关于迪米特法则有一些很形象的比喻： <br />
如果你想让你的狗跑的话，你会对狗狗说还是对四条狗腿说？ <br />
如果你去店里买东西，你会把钱交给店员，还是会把钱包交给店员让他自己拿？ <br />
<br />
和狗的四肢说话？让店员自己从钱包里拿钱？这听起来有点荒唐，不过在我们的代码里这几乎是见怪不怪的事情了。 <br />
<br />
对于LoD，正式的表述如下： <br />
<div style="text-align: center"><br />
<img class="magplus" title="点击查看原始大小图片" src="http://dl.iteye.com/upload/attachment/470338/3fa17f14-b91e-3625-841c-4d6997040367.jpg" width="650" height="120"  alt="" /></div>
<br />
在《Clean Code》一书中，有一段Apache framework中的一段违反了LoD的代码： <br />
<br />
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath(); <br />
<br />
这么长的一串对其它对象的细节，以及细节的细节，细节的细节的细节&#8230;&#8230;的调用，增加了耦合，使得代码结构复杂、僵化，难以扩展和维护。 <br />
<br />
在《重构》一书中的代码的环味道中有一种叫做&#8220;Feature Envy&#8221;(依恋情结），形象的描述了一种违反了LoC的情况。Feature Envy就是说一个对象对其它对象的内容更有兴趣，也就是说老是羡慕别的对象的成员、结构或者功能，大老远的调用人家的东西。这样的结构显然是不合理的。我们的程序应该写得比较&#8220;害羞&#8221;。不能像前面例子中的那个不把自己当外人的店员一样，拿过客人的钱包自己把钱拿出来。&#8220;害羞&#8221;的程序只和自己最近的朋友交谈。这种情况下应该调整程序的结构，让那个对象自己拥有它羡慕的feature，或者使用合理的设计模式（例如Facade和Mediator）。 <br />
<br />
参考：<a href="http://en.wikipedia.org/wiki/Principle_of_Least_Knowledge" target="_blank">http://en.wikipedia.org/wiki/Principle_of_Least_Knowledge</a> <br />
<br />
<strong><span style="color: blue">面向对象的S.O.L.I.D 原则</span></strong> <br />
<br />
一般来说这是面向对象的五大设计原则，但是，我觉得这些原则可适用于所有的软件开发。 <br />
<br />
<strong>Single Responsibility Principle (SRP) &#8211; 职责单一原则</strong> <br />
<br />
关于单一职责原则，其核心的思想是：<strong>一个类，只做一件事，并把这件事做好，其只有一个引起它变化的原因</strong>。单一职责原则可以看作是低耦合、高内聚在面向对象原则上的引申，将职责定义为引起变化的原因，以提高内聚性来减少引起变化的原因。职责过多，可能引起它变化的原因就越多，这将导致职责依赖，相互之间就产生影响，从而极大的损伤其内聚性和耦合度。单一职责，通常意味着单一的功能，因此不要为一个模块实现过多的功能点，以保证实体只有一个引起它变化的原因。 <br />
<br />
Unix/Linux是这一原则的完美体现者。各个程序都独立负责一个单一的事。 <br />
Windows是这一原则的反面示例。几乎所有的程序都交织耦合在一起。 <br />
<br />
<strong>Open/Closed Principle (OCP) &#8211; 开闭原则</strong> <br />
<br />
关于开发封闭原则，其核心的思想是：模块是可扩展的，而不可修改的。也就是说，<strong>对扩展是开放的，而对修改是封闭的</strong>。 <br />
<br />
对扩展开放，意味着有新的需求或变化时，可以对现有代码进行扩展，以适应新的情况。 <br />
对修改封闭，意味着类一旦设计完成，就可以独立完成其工作，而不要对类进行任何修改。 <br />
<br />
对于面向对象来说，需要你依赖抽象，而不是实现，23个经典设计模式中的&#8220;策略模式&#8221;就是这个实现。对于非面向对象编程，一些API需要你传入一个你可以扩展的函数，比如我们的C 语言的qsort()允许你提供一个&#8220;比较器&#8221;，STL中的容器类的内存分配，ACE中的多线程的各种锁。对于软件方面，浏览器的各种插件属于这个原则的实践。 <br />
<br />
<strong>Liskov substitution principle (LSP) &#8211; 里氏代换原则</strong> <br />
<br />
软件工程大师Robert C. Martin把里氏代换原则最终简化为一句话：&#8220;Subtypes must be substitutable for their base types&#8221;。也就是，子类必须能够替换成它们的基类。即：子类应该可以替换任何基类能够出现的地方，并且经过替换以后，代码还能正常工作。另外，不应该在代码中出现if/else之类对子类类型进行判断的条件。里氏替换原则LSP是使代码符合开闭原则的一个重要保证。正是由于子类型的可替换性才使得父类型的模块在无需修改的情况下就可以扩展。 <br />
<br />
这么说来，似乎有点教条化，我非常建议大家看看这个原则个两个最经典的案例——&#8220;正方形不是长方形&#8221;和&#8220;鸵鸟不是鸟&#8221;。通过这两个案例，你会明白《墨子 小取》中说的 ——&#8220;娣，美人也，爱娣，非爱美人也&#8230;.盗，人也；恶盗，非恶人也。&#8221;——妹妹虽然是美人，但喜欢妹妹并不代表喜欢美人。盗贼是人，但讨厌盗贼也并不代表就讨厌人类。<strong>这个原则让你考虑的不是语义上对象的间的关系，而是实际需求的环境。</strong> <br />
<br />
在很多情况下，在设计初期我们类之间的关系不是很明确，LSP则给了我们一个判断和设计类之间关系的基准：需不需要继承，以及怎样设计继承关系。 <br />
<br />
<strong>Interface Segregation Principle (ISP) &#8211; 接口隔离原则</strong> <br />
<br />
接口隔离原则意思是把功能实现在接口中，而不是类中，使用多个专门的接口比使用单一的总接口要好。 <br />
<br />
举个例子，我们对电脑有不同的使用方式，比如：写作，通讯，看电影，打游戏，上网，编程，计算，数据等，如果我们把这些功能都声明在电脑的抽类里面，那么，我们的上网本，PC机，服务器，笔记本的实现类都要实现所有的这些接口，这就显得太复杂了。所以，我们可以把其这些功能接口隔离开来，比如：工作学习接口，编程开发接口，上网娱乐接口，计算和数据服务接口，这样，我们的不同功能的电脑就可以有所选择地继承这些接口。 <br />
<br />
这个原则可以提升我们&#8220;搭积木式&#8221;的软件开发。对于设计来说，Java中的各种Event Listener和Adapter，对于软件开发来说，不同的用户权限有不同的功能，不同的版本有不同的功能，都是这个原则的应用。 <br />
<br />
<strong>Dependency Inversion Principle (DIP) &#8211; 依赖倒置原则</strong> <br />
<br />
高层模块不应该依赖于低层模块的实现，而是依赖于高层抽象。 <br />
<br />
举个例子，墙面的开关不应该依赖于电灯的开关实现，而是应该依赖于一个抽象的开关的标准接口，这样，当我们扩展程序的时候，我们的开关同样可以控制其它不同的灯，甚至不同的电器。也就是说，电灯和其它电器继承并实现我们的标准开关接口，而我们的开关产商就可不需要关于其要控制什么样的设备，只需要关心那个标准的开关标准。这就是依赖倒置原则。 <br />
<br />
这就好像浏览器并不依赖于后面的web服务器，其只依赖于HTTP协议。这个原则实在是太重要了，社会的分工化，标准化都是这个设计原则的体现。 <br />
<br />
参考：<a href="http://en.wikipedia.org/wiki/Solid_(object-oriented_design)" target="_blank">http://en.wikipedia.org/wiki/Solid_(object-oriented_design)</a> <br />
<br />
<span style="color: blue"><strong>Common Closure Principle（CCP）&#8211; 共同封闭原则</strong></span> <br />
一个包中所有的类应该对同一种类型的变化关闭。一个变化影响一个包，便影响了包中所有的类。一个更简短的说法是：一起修改的类，应该组合在一起（同一个包里）。如果必须修改应用程序里的代码，我们希望所有的修改都发生在一个包里（修改关闭），而不是遍布在很多包里。CCP原则就是把因为某个同样的原因而需要修改的所有类组合进一个包里。如果2个类从物理上或者从概念上联系得非常紧密，它们通常一起发生改变，那么它们应该属于同一个包。 <br />
<br />
CCP延伸了开闭原则（OCP）的&#8220;关闭&#8221;概念，当因为某个原因需要修改时，把需要修改的范围限制在一个最小范围内的包里。 <br />
<br />
参考：<a href="http://c2.com/cgi/wiki?CommonClosurePrinciple" target="_blank">http://c2.com/cgi/wiki?CommonClosurePrinciple</a> <br />
<br />
<span style="color: blue"><strong>Common Reuse Principle (CRP) &#8211; 共同重用原则</strong></span> <br />
包的所有类被一起重用。如果你重用了其中的一个类，就重用全部。换个说法是，没有被一起重用的类不应该被组合在一起。CRP原则帮助我们决定哪些类应该被放到同一个包里。依赖一个包就是依赖这个包所包含的一切。当一个包发生了改变，并发布新的版本，使用这个包的所有用户都必须在新的包环境下验证他们的工作，即使被他们使用的部分没有发生任何改变。因为如果包中包含有未被使用的类，即使用户不关心该类是否改变，但用户还是不得不升级该包并对原来的功能加以重新测试。 <br />
<br />
CCP则让系统的维护者受益。CCP让包尽可能大（CCP原则加入功能相关的类），CRP则让包尽可能小（CRP原则剔除不使用的类）。它们的出发点不一样，但不相互冲突。 <br />
<br />
参考：<a href="http://c2.com/cgi/wiki?CommonReusePrinciple" target="_blank">http://c2.com/cgi/wiki?CommonReusePrinciple</a> <br />
<br />
<span style="color: blue"><strong>Hollywood Principle &#8211; 好莱坞原则</strong></span> <br />
好莱坞原则就是一句话——&#8220;don&#8217;t call us, we&#8217;ll call you.&#8221;。意思是，好莱坞的经纪人们不希望你去联系他们，而是他们会在需要的时候来联系你。也就是说，所有的组件都是被动的，所有的组件初始化和调用都由容器负责。组件处在一个容器当中，由容器负责管理。 <br />
<br />
简单的来讲，就是由容器控制程序之间的关系，而非传统实现中，由程序代码直接操控。这也就是所谓&#8220;控制反转&#8221;的概念所在： <br />
<br />
1.不创建对象，而是描述创建对象的方式。 <br />
2.在代码中，对象与服务没有直接联系，而是容器负责将这些联系在一起。 <br />
<br />
控制权由应用代码中转到了外部容器，控制权的转移，是所谓反转。 <br />
<br />
好莱坞原则就是IoC（Inversion of Control）或DI（Dependency Injection ）的基础原则。这个原则很像依赖倒置原则，依赖接口，而不是实例，但是这个原则要解决的是怎么把这个实例传入调用类中？你可能把其声明成成员，你可以通过构造函数，你可以通过函数参数。但是 IoC可以让你通过配置文件，一个由Service Container 读取的配置文件来产生实际配置的类。但是程序也有可能变得不易读了，程序的性能也有可能还会下降。 <br />
<br />
参考： <br />
<br />
[url]http://en.wikipedia.org/wiki/Hollywood_Principle [/url] <br />
[url]http://en.wikipedia.org/wiki/Inversion_of_Control [/url] <br />
<br />
<span style="color: blue"><strong>High Cohesion &amp; Low/Loose coupling &amp; &#8211; 高内聚， 低耦合</strong></span> <br />
这个原则是UNIX操作系统设计的经典原则，把模块间的耦合降到最低，而努力让一个模块做到精益求精。 <br />
<br />
内聚：一个模块内各个元素彼此结合的紧密程度 <br />
耦合：一个软件结构内不同模块之间互连程度的度量 <br />
<br />
内聚意味着重用和独立，耦合意味着多米诺效应牵一发动全身。 <br />
<br />
参考： <br />
<br />
<a href="http://en.wikipedia.org/wiki/Coupling_(computer_science)" target="_blank">http://en.wikipedia.org/wiki/Coupling_(computer_science)</a> <br />
[url]http://en.wikipedia.org/wiki/Cohesion_(computer_science) [/url] <br />
<br />
<span style="color: blue"><strong>Convention over Configuration（CoC）&#8211; 惯例优于配置原则</strong></span> <br />
简单点说，就是将一些公认的配置方式和信息作为内部缺省的规则来使用。例如，Hibernate的映射文件，如果约定字段名和类属性一致的话，基本上就可以不要这个配置文件了。你的应用只需要指定不convention的信息即可，从而减少了大量convention而又不得不花时间和精力啰里啰嗦的东东。配置文件很多时候相当的影响开发效率。 <br />
<br />
Rails 中很少有配置文件（但不是没有，数据库连接就是一个配置文件），Rails 的fans号称期开发效率是 java 开发的 10 倍，估计就是这个原因。Maven也使用了CoC原则，当你执行mvn -compile命令的时候，不需要指源文件放在什么地方，而编译以后的class文件放置在什么地方也没有指定，这就是CoC原则。 <br />
<br />
参考：<a href="http://en.wikipedia.org/wiki/Convention_over_Configuration" target="_blank">http://en.wikipedia.org/wiki/Convention_over_Configuration</a> <br />
<br />
<span style="color: blue"><strong>Separation of Concerns (SoC) &#8211; 关注点分离</strong></span> <br />
SoC 是计算机科学中最重要的努力目标之一。这个原则，就是在软件开发中，通过各种手段，将问题的各个关注点分开。如果一个问题能分解为独立且较小的问题，就是相对较易解决的。问题太过于复杂，要解决问题需要关注的点太多，而程序员的能力是有限的，不能同时关注于问题的各个方面。正如程序员的记忆力相对于计算机知识来说那么有限一样，程序员解决问题的能力相对于要解决的问题的复杂性也是一样的非常有限。在我们分析问题的时候，如果我们把所有的东西混在一起讨论，那么就只会有一个结果——乱。 <br />
<br />
我记得在上一家公司有一个项目，讨论就讨论了1年多，项目本来不复杂，但是没有使用SoC，全部的东西混为一谈，再加上一堆程序员注入了各种不同的观点和想法，整个项目一下子就失控了。最后，本来一个1年的项目做了3年。 <br />
<br />
实现关注点分离的方法主要有两种，一种是标准化，另一种是抽象与包装。标准化就是制定一套标准，让使用者都遵守它，将人们的行为统一起来，这样使用标准的人就不用担心别人会有很多种不同的实现，使自己的程序不能和别人的配合。Java EE就是一个标准的大集合。每个开发者只需要关注于标准本身和他所在做的事情就行了。就像是开发镙丝钉的人只专注于开发镙丝钉就行了，而不用关注镙帽是怎么生产的，反正镙帽和镙丝钉按标来就一定能合得上。不断地把程序的某些部分抽像差包装起来，也是实现关注点分离的好方法。一旦一个函数被抽像出来并实现了，那么使用函数的人就不用关心这个函数是如何实现的，同样的，一旦一个类被抽像并实现了，类的使用者也不用再关注于这个类的内部是如何实现的。诸如组件，分层，面向服务，等等这些概念都是在不同的层次上做抽像和包装，以使得使用者不用关心它的内部实现细节。 <br />
<br />
说白了还是&#8220;高内聚，低耦合&#8221;。 <br />
<br />
参考：<a href="http://sulong.me/archives/99" target="_blank">http://sulong.me/archives/99</a> <br />
<br />
<span style="color: blue"><strong>Design by Contract (DbC) &#8211; 契约式设计</strong></span> <br />
DbC的核心思想是对软件系统中的元素之间相互合作以及&#8220;责任&#8221;与&#8220;义务&#8221;的比喻。这种比喻从商业活动中&#8220;客户&#8221;与&#8220;供应商&#8221;达成&#8220;契约&#8221;而得来。例如： <br />
<br />
供应商必须提供某种产品（责任），并且他有权期望客户已经付款（权利）。 <br />
客户必须付款（责任），并且有权得到产品（权利）。 <br />
契约双方必须履行那些对所有契约都有效的责任，如法律和规定等。 <br />
<br />
同样的，如果在程序设计中一个模块提供了某种功能，那么它要： <br />
<br />
期望所有调用它的客户模块都保证一定的进入条件：这就是模块的先验条件（客户的义务和供应商的权利，这样它就不用去处理不满足先验条件的情况）。 <br />
保证退出时给出特定的属性：这就是模块的后验条件——（供应商的义务，显然也是客户的权利）。 <br />
在进入时假定，并在退出时保持一些特定的属性：不变式。 <br />
<br />
契约就是这些权利和义务的正式形式。我们可以用&#8220;三个问题&#8221;来总结DbC，并且作为设计者要经常问： <br />
<br />
它期望的是什么？ <br />
它要保证的是什么？ <br />
它要保持的是什么？ <br />
<br />
根据Bertrand Meyer氏提出的DBC概念的描述，对于类的一个方法，都有一个前提条件以及一个后续条件，前提条件说明方法接受什么样的参数数据等，只有前提条件得到满足时，这个方法才能被调用；同时后续条件用来说明这个方法完成时的状态，如果一个方法的执行会导致这个方法的后续条件不成立，那么这个方法也不应该正常返回。 <br />
<br />
现在把前提条件以及后续条件应用到继承子类中，子类方法应该满足： <br />
<br />
1.前提条件不强于基类． <br />
2.后续条件不弱于基类． <br />
<br />
换句话说，通过基类的接口调用一个对象时，用户只知道基类前提条件以及后续条件。因此继承类不得要求用户提供比基类方法要求的更强的前提条件，亦即，继承类方法必须接受任何基类方法能接受的任何条件（参数）。同样，继承类必须顺从基类的所有后续条件，亦即，继承类方法的行为和输出不得违反由基类建立起来的任何约束，不能让用户对继承类方法的输出感到困惑。 <br />
<br />
这样，我们就有了基于契约的LSP，基于契约的LSP是LSP的一种强化。 <br />
<br />
参考：<a href="http://en.wikipedia.org/wiki/Design_by_contract" target="_blank">http://en.wikipedia.org/wiki/Design_by_contract</a> <br />
<br />
<span style="color: blue"><strong>Acyclic Dependencies Principle (ADP) &#8211; 无环依赖原则</strong></span> <br />
包之间的依赖结构必须是一个直接的无环图形，也就是说，在依赖结构中不允许出现环（循环依赖）。如果包的依赖形成了环状结构，怎么样打破这种循环依赖呢？有2种方法可以打破这种循环依赖关系：第一种方法是创建新的包，如果A、B、C形成环路依赖，那么把这些共同类抽出来放在一个新的包D里。这样就把C依赖A变成了C依赖D以及A依赖D，从而打破了循环依赖关系。第二种方法是使用DIP（依赖倒置原则）和ISP（接口分隔原则）设计原则。 <br />
<br />
无环依赖原则（ADP）为我们解决包之间的关系耦合问题。在设计模块时，不能有循环依赖。 <br />
<br />
参考：<a href="http://c2.com/cgi/wiki?AcyclicDependenciesPrinciple" target="_blank">http://c2.com/cgi/wiki?AcyclicDependenciesPrinciple</a> <br />
<br />
<img src ="http://www.blogjava.net/paulwong/aggbug/349145.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2011-04-27 23:51 <a href="http://www.blogjava.net/paulwong/archive/2011/04/27/349145.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>门面模式 - Facade Pattern</title><link>http://www.blogjava.net/paulwong/archive/2009/06/17/282730.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Tue, 16 Jun 2009 16:00:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2009/06/17/282730.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/282730.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2009/06/17/282730.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/282730.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/282730.html</trackback:ping><description><![CDATA[无门面模式时:
<div><img src="http://www.blogjava.net/images/blogjava_net/wintys/data_without_facade.jpg" width="421" height="237" alt="" /></div>
<div>有门面模式时:</div>
<div><img src="http://www.blogjava.net/images/blogjava_net/wintys/data_facade.jpg" alt="" /><br />
</div>
<div>
<div style="background-color: #eeeeee; font-size: 13px; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">package</span><span style="color: #000000; ">&#160;pattern.facade;<br />
</span><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />
&#160;*&#160;门面模式/外观模式:Facade&#160;Pattern<br />
&#160;*<br />
&#160;*&#160;保安系统:<br />
&#160;*&#160;一个保安系统由两个录像机、一个感应器和一个报警器组成。<br />
&#160;*&#160;由保安操作仪器的启动和关闭:没有使用门面模式时，保安必须亲自启动每个仪器。<br />
&#160;*&#160;</span><span style="color: #808080; ">@version</span><span style="color: #008000; ">&#160;2009-6-15<br />
&#160;*&#160;</span><span style="color: #808080; ">@author</span><span style="color: #008000; ">&#160;Winty(wintys@gmail.com)<br />
&#160;</span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br />
</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&#160;FacadeTest{<br />
&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&#160;main(String[]&#160;args){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">无门面模式</span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Camera&#160;camera1,camera2;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;camera1&#160;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&#160;Camera();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;camera2&#160;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&#160;Camera();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Sensor&#160;sensor;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;sensor&#160;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&#160;Sensor();<br />
<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Alarm&#160;alarm;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;alarm&#160;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&#160;Alarm();<br />
<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">启动仪器</span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;camera1.turnOn();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;camera2.turnOn();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;sensor.activate();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;alarm.activate();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;System.out.println(</span><span style="color: #000000; ">""</span><span style="color: #000000; ">);<br />
<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</span><span style="color: #008000; ">////////////////////////////////</span><span style="color: #008000; ">/<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">使用门面模式</span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;SecurityFacade&#160;security&#160;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&#160;SecurityFacade();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;security.start();<br />
&#160;&#160;&#160;&#160;}<br />
}<br />
<br />
</span><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />
&#160;*&#160;门面:Facade<br />
&#160;</span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br />
</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&#160;SecurityFacade{<br />
&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&#160;Camera&#160;camera1;<br />
&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&#160;Camera&#160;camera2;<br />
&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&#160;Sensor&#160;sensor;<br />
&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&#160;Alarm&#160;alarm;<br />
<br />
&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;SecurityFacade(){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;camera1&#160;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&#160;Camera();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;camera2&#160;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&#160;Camera();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;sensor&#160;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&#160;Sensor();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;alarm&#160;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&#160;Alarm();<br />
&#160;&#160;&#160;&#160;}<br />
&#160;&#160;&#160;&#160;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">启动</span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&#160;start(){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;camera1.turnOn();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;camera2.turnOn();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;sensor.activate();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;alarm.activate();<br />
&#160;&#160;&#160;&#160;}<br />
<br />
&#160;&#160;&#160;&#160;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">停止</span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&#160;stop(){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;camera1.turnOff();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;camera2.turnOff();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;sensor.deactivate();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;alarm.deactivate();<br />
&#160;&#160;&#160;&#160;}<br />
}<br />
<br />
</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&#160;Camera{<br />
&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&#160;turnOn(){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">turn&#160;on&#160;the&#160;Camera.</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&#160;&#160;&#160;&#160;}<br />
<br />
&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&#160;turnOff(){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">turn&#160;off&#160;the&#160;Camera.</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&#160;&#160;&#160;&#160;}<br />
<br />
&#160;&#160;&#160;&#160;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">转动</span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&#160;rotate(){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">rotate&#160;the&#160;Camera.</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&#160;&#160;&#160;&#160;}<br />
}<br />
<br />
<br />
</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&#160;Sensor{<br />
&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&#160;activate(){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">activate&#160;the&#160;sensor.</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&#160;&#160;&#160;&#160;}<br />
<br />
&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&#160;deactivate(){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">deactivate&#160;the&#160;sensor.</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&#160;&#160;&#160;&#160;}<br />
<br />
&#160;&#160;&#160;&#160;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">触发感应器</span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&#160;trigger(){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">trigger&#160;the&#160;sensor.</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&#160;&#160;&#160;&#160;}<br />
}<br />
<br />
</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&#160;Alarm{<br />
&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&#160;activate(){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">activate&#160;the&#160;alarm.</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&#160;&#160;&#160;&#160;}<br />
<br />
&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&#160;deactivate(){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">deactivate&#160;the&#160;alarm.</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&#160;&#160;&#160;&#160;}<br />
<br />
&#160;&#160;&#160;&#160;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">拉响报警器</span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">&#160;&#160;&#160;&#160;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&#160;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&#160;ring(){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">ring&#160;the&#160;alarm.</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&#160;&#160;&#160;&#160;}<br />
}&#160;<br />
</span></div>
<div style="background-color: #eeeeee; font-size: 13px; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; "><br />
</div>
<div style="background-color: #eeeeee; font-size: 13px; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; ">
<div style="background-color: #eeeeee; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; ">运行结果:</div>
<div style="background-color: #eeeeee; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; ">turn on the Camera.</div>
<div style="background-color: #eeeeee; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; ">turn on the Camera.</div>
<div style="background-color: #eeeeee; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; ">activate the sensor.</div>
<div style="background-color: #eeeeee; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; ">activate the alarm.</div>
<div style="background-color: #eeeeee; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; "><br />
</div>
<div style="background-color: #eeeeee; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; ">turn on the Camera.</div>
<div style="background-color: #eeeeee; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; ">turn on the Camera.</div>
<div style="background-color: #eeeeee; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; ">activate the sensor.</div>
<div style="background-color: #eeeeee; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; ">activate the alarm.</div>
</div>
</div>
<img src ="http://www.blogjava.net/paulwong/aggbug/282730.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2009-06-17 00:00 <a href="http://www.blogjava.net/paulwong/archive/2009/06/17/282730.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>進銷存系統有幾個資料庫？</title><link>http://www.blogjava.net/paulwong/archive/2006/06/17/53451.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Sat, 17 Jun 2006 01:57:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2006/06/17/53451.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/53451.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2006/06/17/53451.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/53451.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/53451.html</trackback:ping><description><![CDATA[
		<p>我在教授
軟體設計課程，尤其是以使用案例圖在說明架構設計時，每一個用套件(Package)所界定範圍的系統，係指軟體應用系統，但卻幾乎不會談及到資料庫。因
為，軟體應用系統與資料庫是兩個不同的層次，甚至，把資料庫視為是應用系統的 "私有倉儲(private storage)"，會比較恰當。</p>
		<p>
				<br />
		</p>
		<p>不過，這衍生出一個問題，學員不容易分清楚如何 "mapping" 抽象面的架構設計至實體的 IT 系統，尤其是資料庫的問題。所以，我會先帶一個問題問學員：<strong>在設計層次的考量中，進銷存系統有幾個資料庫？</strong></p>
		<p>
				<strong>
						<br />
				</strong>
		</p>
		<p>這一個問題要能回答得出來，其假設前提的考量必須要瞭解，在整體的架構設計中，設計團隊到底將 "進銷存" 視為是一個，還是三個，甚至多個的子系統？</p>
		<p>
				<br />
		</p>
		<p>參考下圖1，這是把 "進銷存" 視為是單一的系統，所以，<strong>資料庫只有一個。</strong></p>
		<p>
				<strong>
				</strong>
				<br />
好處是什麼？ 就是簡單，開發也容易。進銷存相關的資訊處理，都是在同一個資料庫內，並沒有分散的問題，所以當處理銷貨需要查詢庫存資訊時，只要下 SQL 敘述直接連結庫存的 TABLE 即可。</p>
		<br />
		<p>
				<img src="file:///C:/DOCUME%7E1/Paul/LOCALS%7E1/Temp/moz-screenshot.jpg" alt="" />
				<img src="http://www.kenming.idv.tw/mybase/soft_imgs/in_sale_stock_system_01.jpg" />
		</p>
		<br />
		<p>
				<font color="red" size="-1">圖1、將進銷存視為一個整體系統</font>
		</p>
		<p>
				<font color="red" size="-1">
						<br />
				</font>
		</p>
		<p>參考下圖2，架構設計之初時，就已把 "進銷存"
分為三個子系統(Sub-system)，或者也可以稱之為元件(Component)，以凸顯子系統之間的溝通，是透過介面(Interface)的呼
叫。其實，論子系統的範圍與規模，稱為 "模組(Module)" 更為適合，不過，我個人並不喜歡以 "模組"
二字來稱之，因為，這個術語被業界給濫用了，已淪落為在業務面的術語，卻並沒有在實體的系統間，嚴格遵循透過介面的呼叫。</p>
		<p>
				<br />
		</p>
		<p>所以圖2，<strong>有三個資料庫。</strong></p>
		<p>
				<strong>
				</strong>
				<br />
當銷貨人員處理銷貨需要查詢庫存資訊時，需要透過庫存系統所提供的介面來呼叫，介面的實做可能是 "Web Service"、"Java
Bean"、"Session Bean"、"COM+" 等，但絕對不能直接下 SQL
來呼叫位於庫存系統內的資料庫，否則，就違背了圖2的整體架構設計。不遵循整體架構設計的規範，私自偷偷連接，稱之為 "跳線"。</p>
		<p>
				<br />
		</p>
		<br />
		<p>
				<img src="http://www.kenming.idv.tw/mybase/soft_imgs/in_sale_stock_system_02.jpg" />
		</p>
		<font color="red" size="-1">圖2、將進銷存分成三個獨立的子系統<br /><br /></font>
		<p>上圖2的抽象設計與IT面的實做技術，比較困難，也需要花較多成本，以專案為主(Project-based)的開發，時程短、預算
低廉，不容易達成圖2的設計目標。但若重覆性的專案，專注在進銷存這個領域上，有豐富足夠的領域知識(Domain
Knowledge)，且打算產品化(Product)，那麼，圖2的系統架構來得有彈性很多，"進"、"銷"、"存"
三個子系統(元件)，均可以隨意抽換，各自更新或改版，而不會影響到另一個子系統，如同 PC 主機板內的硬體元件，可以造成 "PnP(Plug
and Play)" 的效果。</p>
		<p>
				<br />
		</p>
		<p>請注意，上述問題的提問，會有幾個資料庫，是指抽象的邏輯設計層面，可千萬不要與實體的資料庫混為一
談。例如，圖2雖然需要三個資料庫，但若以 Oracle 資料庫系統，DBA 可以將邏輯層面的三個資料庫，切分為三個 "TABLE
SPACE"，然後放在同一個實體的 Oracle 資料庫系統內；而若是 MS SQL 或是 MySQL，則是切割為三個
"database"，放入同一個實體資料庫系統內。</p>
		<p>
				<br />
		</p>
		<p>當然，若有地理位置或資料庫系統負載的問題，要分散至多個實體的資料庫系統，那也沒問題。例如，進銷存位於三個地點不同的廠，各自配置了三個實體資料庫，各自存放自己的資訊。這也是圖2架構設計的優點，一切<strong>分合自如！</strong></p>
		<p>
				<strong>
						<br />
				</strong>
		</p>
		<p>e
化的系統設計，即使是 ERP
如此重視資料存取與處理的系統，應該要能摒除傳統以資料庫為中心的設計觀點，因為，系統整體的彈性度會不佳，很難應變需求面的頻繁變更，或是 IT
實體平台，包括資料庫系統的變更等。設計重心應該要轉移至 "Middleware"，這個術語可能太貼近 IT
平台面了，倒不如乾脆這麼說，設計的重心就是回歸至以 "應用系統"
為主，是觀察應用系統可以提供那些服務(services)或功能(functions)，這些服務與功能其實就是系統一個個可以量化的子目標(Sub-
goal)，次一步驟才是考量如何取得要能達成這些子目標的資訊(資料)，要取得資訊，就是到實體的倉儲，也就是私有的資料庫系統去找，或是，透過標準的
程序，也就是透過標準的介面，至外部系統取得相關的資訓來處理。
</p>
<img src ="http://www.blogjava.net/paulwong/aggbug/53451.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2006-06-17 09:57 <a href="http://www.blogjava.net/paulwong/archive/2006/06/17/53451.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>