<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>软件开发</title><link>http://www.iduu.net:80/develop</link><description>软件开发</description><item><title>实现模式读书摘要-实现模式的价值</title><link>http://www.iduu.net:80/develop/%E5%AE%9E%E7%8E%B0%E6%A8%A1%E5%BC%8F%E8%AF%BB%E4%B9%A6%E6%91%98%E8%A6%81</link><description>&lt;p&gt;沟通、简单和灵活的价值观应当被所有开发人员所铭记。局部影响、最小化重复、将逻辑与数据捆绑等原则同样是通用性的指导思想，比价值观更贴近编程场景，在价值观和模式之间搭建了桥梁。&lt;/p&gt;
&lt;p&gt;在《实现模式》一书的77种实现模式中，每一种模式都覆盖了编写简洁、清晰、易扩展的代码这一原则的某个方面。《实现模式》的关于&amp;ldquo;如何编写别人能懂的代码&amp;rdquo;的书。本书介绍的实现模式正是一些编程习惯，他们能让你编写出的代码更加易读。&lt;/p&gt;
&lt;p&gt;有一个叫做Jeopardy的美国游戏节目，由主持人给出问题的答案，参赛观众则来猜问题是什么。&amp;ldquo;猜一个词，表示扔出窗外。&amp;rdquo;&lt;br /&gt;&amp;ldquo;是defenestration吗？&amp;rdquo;&lt;br /&gt;&amp;ldquo;答对了。&amp;rdquo;&lt;br /&gt;编程就好像Jeopardy游戏：答案用Java的基本语言构造给出，程序员则经常要找出问题究竟是什么，既这些语言构造究竟是在解决什么问题。&lt;br /&gt;比如说，如果答案是&amp;ldquo;把一个字段声明为Set&amp;rdquo;，那么问题可能就是&amp;ldquo;我要怎样告诉其他程序员，这是一个不允许包含重复元素的集合?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description><pubDate>Thu, 11 Aug 2011 01:00:59 GMT</pubDate><guid isPermaLink="true">http://www.iduu.net:80/develop/%E5%AE%9E%E7%8E%B0%E6%A8%A1%E5%BC%8F%E8%AF%BB%E4%B9%A6%E6%91%98%E8%A6%81</guid></item><item><title>实现模式读书摘要-模式实践2</title><link>http://www.iduu.net:80/develop/%E5%AE%9E%E7%8E%B0%E6%A8%A1%E5%BC%8F%E8%AF%BB%E4%B9%A6%E6%91%98%E8%A6%81-%E6%A8%A1%E5%BC%8F%E5%AE%9E%E8%B7%B52</link><description>&lt;p&gt;&lt;strong&gt;实现模式:类&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;数据的变化比逻辑要频繁的多，正是这种现象让类有了存在的意义。每个类其实就是这样一个声明：这些逻辑应该放在一起，它们的变化不像他们所操作的数据那么频繁；这些数据也应该放在一起，它们的 变化频率差不多，并且由与之相关的逻辑来负责处理。&lt;/p&gt;
&lt;p&gt;这种&amp;ldquo;数据会变、逻辑不变&amp;rdquo;的划分并非绝对适用：有时随着数据值的不同，逻辑也会有所不同；有时逻辑也会发生相当大的变化；有时数据本身在计算的过程中反倒不会改变。学会如何用类来包装逻辑和如何表达逻辑的变化，这是有效使用对象编程的重要部分。&lt;/p&gt;
&lt;p&gt;把多个类放进一个继承体系可以缩减代码量，比不原封不动的把超类的内容抄到子类精简的多。和所有缩减代码量的技巧一样，它也让代码变的更难读懂；必须理解超类的上下文，然后才有可能理解子类。&lt;/p&gt;
&lt;p&gt;在由对象搭建而成的程序中，类是相对昂贵的设计元素。一个类应该做一些直接而明显的意义的事情。减少类的数量是对系统的改进，只要剩下的类不因此而变的臃肿就好。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现模式:简单的超类名&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;照到一个贴切的名字是编程中最令人开心的时刻之一。在所有的命名当中，类的命名是最重要的。类是维系其他概念的核心。一旦类有了名字，其中操作的名字也就顺利成章了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现模式:限定性的子类名&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;子类的名字有两重职责，不仅要描述这些类像什么，还要说明他们之间的区别是什么。同样，在这里需要权衡长度和表现力。与位于继承体系根上的超类不同，子类的名字在交谈中用的并不频繁，所以值得以牺牲简明来换取更好的表现力。通常在超类名的基础上扩展一两个词就可以得到子类名。&lt;/p&gt;
&lt;p&gt;与他人沟通时类名的用途，如果仅仅为了和计算机沟通，只要给每个类编号就足够了。太长的类名读写都费劲，太短的类名又会考验读者的记忆力。如果一组类的名字体现不出他们之间的相关性，阅读者就很难对它们形成整体印象，也很难回忆起它们的关系。应该用类名来讲述代码的故事。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现模式:抽象接口&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;请牢记软件开发的古训：针对接口编程，不要针对实现编程。从另一个角度来说，这也意味着设计决策不应该暴露给不必要的地方。如果大部分代码只知道我在处理一个容器，那么我就可以随时改变这个容器的具体实现。但有时不得不指定具体类，否则计算就没法进行下去。&lt;/p&gt;
&lt;p&gt;这里所说的&amp;ldquo;接口&amp;rdquo;是指&amp;ldquo;一组没有实现的操作&amp;rdquo;。接口这个概念既可以表现为interface，也可以表现为超类。随后的两个模式会分别指出两者的适用场景。&lt;/p&gt;
&lt;p&gt;每层接口都是成本。并不是接口数量越多软件成本就越少，只有需要接口带来的灵活性时才值得为它付出成本。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现模式:interface&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;要用java表达&amp;ldquo;这是我要完成的任务，除此之外的细节不归我操心&amp;rdquo;，可以声明一个interface。Interface是一个很好的平衡，它带来了多继承的一部分灵活性，同时又没有多继承的复杂性和二义性。&lt;/p&gt;
&lt;p&gt;如果说interface让改变的工作更加轻松，那么不能不提的是对接口本身的修改时不被鼓励的；一旦在interface上增加或修改方法，就必须同时改变所有的实现接口的类。如果无权改变实现，大量使用接口会严重拖累日后的设计调整。&lt;/p&gt;
&lt;p&gt;此外interface的一个特点也影响了他们作为沟通手段的价值：其中所有的操作都必须是public的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现模式:抽象类&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在java中区分抽象接口和具体实现的另一种方式是使用超类。超类是抽象的，因为超类的引用可以再运行时替换为任何子类的对象；至于这个超类在java中的语法意义上是不是抽象的，这并不重要。&lt;/p&gt;
&lt;p&gt;是应该使用超类还是应该使用interface？取舍最终归结为两点：接口会如何变化，实现类是否需要同时支持多个接口。&lt;/p&gt;
&lt;p&gt;抽象接口需要支持实现的变化以及接口本身的变化两种类型的变化。Interface对接口本身的变化支持不佳；一旦改变interface，所有的实现类都必须同时修改。抽象类则没有这方面的限制。只要提供了默认实现，在抽象类中新增的操作就不会侵扰现有的实现类。&lt;/p&gt;
&lt;p&gt;抽象类的局限体现在实现类必须对其忠心不贰。如果需要以另一种视角来看待同一个实现类，就只能让它实现interface了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现模式:有版本的interface&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果想要修改一个interface但又不能修改，怎么办？这种情况通常在想要增加操作是发生，在interface中增加操作会破坏所有现有的实现类，所以不能这样做。不过可以声明一个新的interface，使它继承原来的interface,然后在其中增加操作。如果使用者需要新增的功能，就使用这个新的interface，其他的使用者则继续无视新interface的存在。使用这种做法，在需要新功能是必须明确检查对象的类型，并将其向下转型为新interface的类型。&lt;/p&gt;
&lt;p&gt;interface能很好的适应实现的变化，却不容易适用自身结构的变化。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description><pubDate>Mon, 01 Aug 2011 01:00:22 GMT</pubDate><guid isPermaLink="true">http://www.iduu.net:80/develop/%E5%AE%9E%E7%8E%B0%E6%A8%A1%E5%BC%8F%E8%AF%BB%E4%B9%A6%E6%91%98%E8%A6%81-%E6%A8%A1%E5%BC%8F%E5%AE%9E%E8%B7%B52</guid></item><item><title>实现模式读书摘要-模式实践1</title><link>http://www.iduu.net:80/develop/%E5%AE%9E%E7%8E%B0%E6%A8%A1%E5%BC%8F%E8%AF%BB%E4%B9%A6%E6%91%98%E8%A6%81-%E6%A8%A1%E5%BC%8F%E5%AE%9E%E8%B7%B51</link><description>&lt;p&gt;&lt;strong&gt;实现模式：局部化影响&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;组织代码结构时，要保证变化只会产生局部化影响。如果这里的一个变化会引起那里的一个问题，那么变化的代价就会急剧上升了。把 影响范围缩到最小，代码就会有极佳的沟通效果。它可以被逐步深入理解，不必一开始就要鸟瞰全景。&lt;/p&gt;
&lt;p&gt;因为实现模式背后一条最主要的动机就是减少变化所引起的代价，所以局部化影响这条原则也是很多模式的形成缘由之一。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现模式：最小化重复&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最小化重复这条原则有助于保证局部化影响。如果相容的代码出现在很多地方，那么修改其中一处副本时，就不得不考虑是否需要修改其他副本；变动不再只发生在局部。代码的复制越多，变化的代价就越大。&lt;/p&gt;
&lt;p&gt;我们可以把程序拆分成许多更小的部分&amp;mdash;&amp;mdash;小段语句、小段方法、小型对象和小型包，从而消除重复。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现模式：将逻辑与数据捆绑&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;局部化影响的必然结果就是将逻辑与数据捆绑。把逻辑和逻辑所处理的数据放在一起，如果有可能尽量放到一个方法中，或则退一步，放到一个对象里面，最起码也要放到一个包下面。在发生变化时，逻辑和数据很可能会同时被改动。如果它们被放在一起，那么修改它们所造成的影响就会只停留在局部。&lt;/p&gt;
&lt;p&gt;在编码开始的是时候，我们往往不太清楚该把逻辑和数据放在哪里。可能在A中编写代码的时候才意识到需要B中的数据。在代码正常工作之后，我才意识到它与数据离的太远。这时候需要做出选择：是该把代码挪到数据那边，还是把代码挪到逻辑这边来，或者把代码和逻辑都放到一个辅助的对象中？也许还可能意识到，这时我还没法找出组合它们以便增进沟通的最好方式。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现模式：对称性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对称性也是我随时运用的一项原则。程序中处处充满了对称性。比如add()方法总会伴随着remove()方法，一组方法会接受相同的参数，一个对象中所有的字段都具有相同的生命周期。识别出对称性，把它清晰的表述出来，代码将更容易阅读。一旦阅读者理解了对称性所涵盖的某一半，他们就会很快的理解另一半。&lt;/p&gt;
&lt;p&gt;程序中的对称性指的是概念上的对称。代码中对称的表现是无论在什么地方，相同的概念都以相同的形式呈现。这是一个缺少对称性的例子：&lt;/p&gt;
&lt;p&gt;void process(){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;input();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;count++;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;output();&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;/p&gt;
&lt;p&gt;第二条语句比其他的语句更加具体。我会根据对称性的原则重写它，结果是：&lt;br /&gt;void process(){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; input();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; incrementCount();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; output();&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;/p&gt;
&lt;p&gt;这个方法依然违反了对称性。这里的input()和output()操作都是通过方法意图来命名的。但是incrementCount()这个方法却以实现方式来命名。在追求对称性的时候，我会考虑为什么我会增加这个数值，于是就有了下面的结果：&lt;br /&gt;&amp;nbsp;&amp;nbsp;void process(){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; input();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; tally();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; output();&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;/p&gt;
&lt;p&gt;在准备消灭重复之前，常常需要寻找并表示出代码中的对称性。如果在很多代码中都存在类似的想法，那么可以先把它们用对称的方式表示出来，接下来的重构有一个良好的开端。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现模式:声明式表达&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;实现模式背后的另一条原则是尽可能声明式的表达出意图。命令式编程语言功能强大灵活，但是在阅读时需要跟随着代码的执行流程。我必须在大脑里建立起一个程序状态，控制流和数据流的模型。对于那些只是陈诉简单事实，不需要一系列条件语句的程序片段，如果用简单的声明方式写出来，读着就容易多了。&lt;/p&gt;
&lt;p&gt;比如在JUnit的早期版本中，测试类里可能会有一个静态的suite()方法，改方法会返回需要运行的测试集合。&lt;/p&gt;
&lt;p&gt;public static junit.framework.Test suite(){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Test result = new TestSuite();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;hellip;complicated stuff&amp;hellip;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;return result;&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;/p&gt;
&lt;p&gt;现在就有了一个很简单很常见的问题：那些测试会被执行？在大对数情况下，suite()方法只是将多个类中的测试汇总起来。但是因为他是一个通用方法，所以我必须要读过，理解该方法后，才能够百分之百确定他的功能。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现模式:变化率&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最后一个原则就是把具有相同变化率的逻辑、数据放在一起，把具有不同变化率的逻辑、数据分离。&lt;/p&gt;
&lt;p&gt;变化率具有时间上的对称性。有是时候可以将变化率原则应用于人为的变化。例如，如果开发一套税务软件，我会把计算通用税金的代码和计算某年特定税金的代码分离开。两类代码的变化率是不同的。在下一年中做调整的时候，我会希望能够确保上一年中的代码依然奏效。分离两类代码可以让我更确信每年的修改只会产生局部化的影响。&lt;/p&gt;
&lt;p&gt;变化率原则也适用于数据。对一个对象中所有成员变量的变化率应该差不多时相同的。只会在一个方法的声明周期内修改的成员变量应该是局部变量。两个同时变化但又和其他成员的变化步调不一致的变量可能应该属于某个辅助对象。比如金融票据的数值与币种会同时变化，那么这两个字段最好放到一个辅助对象Money中：&lt;/p&gt;
&lt;p&gt;setAmount(int value,string currency){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.value = value;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.currency = currency;&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;/p&gt;
&lt;p&gt;上面这段代码就变成 了：&lt;br /&gt;&amp;nbsp;&amp;nbsp;setAmount(int value, string currency){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.value = new Money(value, currency);&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;/p&gt;
&lt;p&gt;然后进一步调整：&lt;br /&gt;&amp;nbsp;&amp;nbsp;setAmount(Money value){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.value = value;&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;/p&gt;
&lt;p&gt;变化率原则也是对称性的一个应用，不过是时间上的对称。上面的例子中，value和currency两个初始字段是对称的，它们会同时变化。但他们与对象中其他字段是不对称的。把它们放到自己应该从属的对象中，让新的对象向阅读者传达出它们的对称关系，这样就更有可能在将来消除重复，进一步达到影响的局部化。&lt;/p&gt;</description><pubDate>Sun, 31 Jul 2011 03:00:08 GMT</pubDate><guid isPermaLink="true">http://www.iduu.net:80/develop/%E5%AE%9E%E7%8E%B0%E6%A8%A1%E5%BC%8F%E8%AF%BB%E4%B9%A6%E6%91%98%E8%A6%81-%E6%A8%A1%E5%BC%8F%E5%AE%9E%E8%B7%B51</guid></item><item><title>实现模式读书摘要-一种编程理论</title><link>http://www.iduu.net:80/develop/%E5%AE%9E%E7%8E%B0%E6%A8%A1%E5%BC%8F%E8%AF%BB%E4%B9%A6%E6%91%98%E8%A6%81-%E4%B8%80%E7%A7%8D%E7%BC%96%E7%A8%8B%E7%90%86%E8%AE%BA</link><description>&lt;p&gt;每个模式都承载着一点点理论。但实际编程中存在一些更加深广的影响力，远不是孤立的模式所能概括的。本章将会讲述这些贯穿于编程中的横切概念，它们被分为两类：价值观和原则。&lt;/p&gt;
&lt;p&gt;价值观是编程过程中的统一支配性主题。珍视与其他人沟通的重要性，把代码中多余的重复性去掉，并保持开放的心态，这才是我们工作状态最佳的表现。&lt;/p&gt;
&lt;p&gt;这些价值观&amp;mdash;&amp;mdash;&lt;strong&gt;沟通、简单和灵活&lt;/strong&gt;&amp;mdash;&amp;mdash;影响了我们在编程时所做的每个决定。&lt;/p&gt;
&lt;p&gt;价值观、原则和模式的关系：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;价值观有普遍的意义，但是往往难以直接应用；&lt;/li&gt;
&lt;li&gt;模式虽可以直接应用，却是针对于特定的情景；&lt;/li&gt;
&lt;li&gt;原则在价值观和模式之间搭建了桥梁。&lt;/li&gt;
&lt;li&gt;模式描述了要做什么，价值观提供了动机，原则把动机转化成了实际行动。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;价值观&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;沟通&amp;mdash;&amp;mdash;如果阅读者可以理解某段代码，并且进一步修改或使用它，那么这段代码的沟通效果的很好。&lt;/p&gt;
&lt;p&gt;简单&amp;mdash;&amp;mdash;去掉多余的重复性可以让那些阅读、使用和修改代码的人更容易理解。有些复杂性是内在的，它们准确的反应出所要解决的问题的复杂性。但有些复杂性的产生完全是因为我们忙着让程序运行起来，在摆弄的过程中留下的&amp;ldquo;指甲印&amp;rdquo;没擦干净。这种多余的复杂性降低了软件的价值。&lt;/p&gt;
&lt;p&gt;灵活&amp;mdash;&amp;mdash;灵活是衡量那些低效编码与设计实践的一把标尺。因为程序的绝大部分开销都是在它第一次部署以后才长生，所以程序必须要容易修改。想象中明天或许会用得上的灵活性，可能与真正修改代码时需要的灵活不是一回事。这就是简单性和大规模测试所带来的灵活性比专门设计出来的灵活性更有效的原因。要选择那些提倡灵活性并能够带来及时收益的模式。对于会立刻增加成本但却缓慢的模式，最好让自己多一点耐心，先把它们放回口袋里，需要的时候再拿出来。这样就可以用最恰当的方式使用它们。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原则&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;实现模式并不是无缘无故产生的。每一种模式都或多或少体现了沟通、简单和灵活这些价值观。原则是另一个层次上的通用思想，比价值观更贴近于编程实际，同时又是模式的基础。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description><pubDate>Sat, 30 Jul 2011 02:00:28 GMT</pubDate><guid isPermaLink="true">http://www.iduu.net:80/develop/%E5%AE%9E%E7%8E%B0%E6%A8%A1%E5%BC%8F%E8%AF%BB%E4%B9%A6%E6%91%98%E8%A6%81-%E4%B8%80%E7%A7%8D%E7%BC%96%E7%A8%8B%E7%90%86%E8%AE%BA</guid></item><item><title>实现模式读书摘要-模式</title><link>http://www.iduu.net:80/develop/%E5%AE%9E%E7%8E%B0%E6%A8%A1%E5%BC%8F%E8%AF%BB%E4%B9%A6%E6%91%98%E8%A6%811</link><description>&lt;p&gt;绝大多数程序都遵循一组简单的法则。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更多的时候，程序都是被阅读，而不是被编写。&lt;/li&gt;
&lt;li&gt;没有&amp;ldquo;完工&amp;rdquo;一说。修改程序的投入都远大于最初编写程序的投入。&lt;/li&gt;
&lt;li&gt;程序都由一组基本的语句和控制流概念组合而成。&lt;/li&gt;
&lt;li&gt;程序的阅读者需要理解程序&amp;mdash;&amp;mdash;即从细节上，也从概念上。有时候从细节开始，逐渐理解概念；有时候从概念开始，逐渐理解细节。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;模式就是基于这样的共性之上的。比如说，每个程序员都必须决定如何进行迭代遍历。在思考如何写出循环的时候，大部分领域问题都被暂时抛在脑后了，留下的就是纯技术问题：这个循环应该容易读懂，容易编写，容易验证，容易修改，而且高效。&lt;/p&gt;
&lt;p&gt;让你操心的这一系列事情，就是模式的起源。上面列出的这些约束，或者叫压力，会影响到程序中每个循环编写的方式。可以预见到，这样的压力会不断重现，这也正是模式之所以成为模式的原因：它其实是关于压力的模式。&lt;/p&gt;
&lt;p&gt;有好几种合理的方式可以写出一个循环，它们分别暗含着对这些约束的不同的优先级排序：如果性能更重要，你可以用这种方式来写循环；如果容易修改更重要，你就可能用另一种方式来写循环。&lt;/p&gt;</description><pubDate>Fri, 29 Jul 2011 01:00:04 GMT</pubDate><guid isPermaLink="true">http://www.iduu.net:80/develop/%E5%AE%9E%E7%8E%B0%E6%A8%A1%E5%BC%8F%E8%AF%BB%E4%B9%A6%E6%91%98%E8%A6%811</guid></item><item><title>TDD-软件中所表示的模型</title><link>http://www.iduu.net:80/develop/TDD-%E8%BD%AF%E4%BB%B6%E4%B8%AD%E6%89%80%E8%A1%A8%E7%A4%BA%E7%9A%84%E6%A8%A1%E5%9E%8B</link><description>&lt;p&gt;一、&amp;nbsp;关联&lt;/p&gt;
&lt;p&gt;对象之间的关联使得建模与实现之间的交互更为复杂。&lt;/p&gt;
&lt;p&gt;一个显示了顾客与销售代表之间关联的模型有两个含义。一方面，它把开发人员所认为的两个真实人之间的关系抽象出来。另一方面，它相当于两个java对象之间的对象指针，或者相当于数据库查询的一种封装。&lt;br /&gt;例如，一对多关联在实例变量中可以用一个集合来实现。也可以使用一种访问方法来查询数据库，找到相应的记录，并用这些记录来实例化对象。在设计中必须制定一种特殊的遍历机制，这种遍历的行为应该于模型中的关系一致。&lt;br /&gt;现实生活中有大量的&amp;ldquo;多对多&amp;rdquo;关联，其中有很多关联自然而然是双向的。这些普遍的关联会使实现和维护变得很复杂。此外，他们也很少能表示出关系的本质。&lt;/p&gt;
&lt;p&gt;至少有三种方法可以使关联更易于控制。&lt;/p&gt;
&lt;p&gt;1)&amp;nbsp;规定一个遍历方向&lt;br /&gt;2)&amp;nbsp;添加一个限定符，以便有效的减少多重关联。&lt;br /&gt;3)&amp;nbsp;消除不必要的关联。&lt;/p&gt;
&lt;p&gt;尽可能地对关系进行约束是非常重要的。双向关联意味着只有将这两个对象放在一起考虑才能理解他们。当应用程序不需要双向遍历时，可以指定一个遍历方向，以便减少相互依赖性，并简化设计。理解了领域之后就可以自然的确定一个方向。国家与总统的关联Brokerage Account中的关联&lt;/p&gt;
&lt;p&gt;二、&amp;nbsp;模式：Entity&lt;/p&gt;
&lt;p&gt;一些对象主要不是由它们的属性定义的。它们实际上表示了一条&amp;ldquo;标识线&amp;rdquo;，这条线经过了一个时间跨度，而且对象在这条线上通常经历了多种不同的表示。有时，这样的对象必须与另一个具有不同属性的对象相匹配。而有时一个对象必须与具有相同属性的另一个对象区分开。错误的标识可能会破坏数据。&lt;/p&gt;
&lt;p&gt;主要由标识定义的对象称为Entity。Entity(实体)有特殊的建模和设计思路。它们具有生命周期，这期间它们的形式和内容可能发生根本改变，但其标识保持不变。模型必须定义出&amp;ldquo;符合什么条件才算是相同的事物&amp;rdquo;。在现实世界中，并不是每个事物都必须有一个标识，标识重不重要，完全取决于它是否有用。实际上，现实世界中的同一个事物在领域模型中可能需要表示为Entity，也可能不需要表示为Entity。例如：体育场的座位。&lt;/p&gt;
&lt;p&gt;Entity建模&lt;/p&gt;
&lt;p&gt;当对一个对象进行建模时，需要考虑它的属性和行为。但Entity的最基本职责是确保连续性，以便使其行为更清楚且可预测。保持实体的简练是实现这一职责的关键。不要将注意力集中在属性和行为上，应该摆脱这些细枝末节，抓住Entity对象定义的基本特征，尤其是那些用于识别、查询和匹配对象的特征。只添加那些对概念至关重要的行为和这些行为所必需的属性。此外，应该将行为和属性转移到与核心实体关联的其他对象中。在这些对象中，有些可能是Entity，有些可能是Value Object。除了标识问题之外，实体往往通过协调其对象的操作来完成自己的职责。&lt;/p&gt;
&lt;p&gt;设计标识操作&lt;/p&gt;
&lt;p&gt;每个Entity都必须有一种建立标识的操作方式，以便与其他对象区分开，即使这些对象与它具有相同的描述属性。两个对象是同一个事物时意味着什么？我们很容易为每个对象分配一个ID，或是编写一个用于比较两个实例的操作，但如果这些ID或操作在领域中并没有显著的区别，那么只会使问题更混乱。这就是分配标识的操作通常需要人工输入的原因。例如：支票薄对账软件可以提供一些可能匹配的账目，但它们是否真的匹配则要由用户最终决定。&lt;/p&gt;
&lt;p&gt;三、&amp;nbsp;模式：Value Object&lt;/p&gt;
&lt;p&gt;很多对象没有概念上的标识，它们描述了一个事务的某些特征。用于描述领域的某个方面而本身没有概念标识的对象称为Value Object（值对象）。Value Object被实例化以后用来表示一些设计元素，我们只关心这些元素是什么，而不关心它们是谁。&amp;ldquo;地址&amp;rdquo;是Value Object吗？当我们只关心一个模型元素时，应把它归类为Value Object。我们应该使这个模型元素能够表示出其属性的意义，并为它提供相关功能。Value Object应该是不可变的。不要为它分配任何标识，而且不要把它设计成像Entity那么复杂。Value Object所包含的属性应该形成一个概念整体。例如，street,city和postal code不应该是person对象的单独属性。它们是整地址的一部分，这样可能使得Person对象更简单，并使它成为一个更连贯的Value Object。&lt;/p&gt;
&lt;p&gt;设计Value Object&lt;/p&gt;
&lt;p&gt;我们并不关心使用的是Value Object的哪个实例。由于不受这方面的约束，设计可以获得更大的自由，因此可以简化设计或优化性能。在设计Value Object时有多种选择，包括复制、共享或保持Value Object不变。&lt;br /&gt;共享和复制哪个更划算取决于实现环境。&lt;/p&gt;
&lt;p&gt;四、&amp;nbsp;模式：Service&lt;/p&gt;
&lt;p&gt;在某些情况下，最清楚、最使用的设计会包含一些特殊的操作，这些操作从概念上讲不属于任何对象。与其把它们强制地归于哪一类，不如顺其自然的在模型中引入一种新的元素，这就是Service（服务）。一些领域概念不适合被建模为对象。如果勉强的把这些重要的领域功能归为Entity或Value Object的职责，那么不是歪曲了基于模型的对象的定义，就是人为地增加了一些无意义的对象。Service是作为接口提供的一种操作，它在模型中式独立的。所谓Service，它强调的是与其他对象的关系。与Entity和Value Object不同，它只是定义了能够为客户做什么。Service是以一个活动命名，而不是以一个Entity命名，也就是说它是动词而不是名词。&lt;/p&gt;
&lt;p&gt;Service的参数和结果应该是领域对象。好的Service有以下3个特点：&lt;/p&gt;
&lt;p&gt;1)&amp;nbsp;与领域概念相关的操作不是Entity或Value Object的一个自然的部分。&lt;br /&gt;2)&amp;nbsp;接口是根据领域模型的其他元素定义的。&lt;br /&gt;3)&amp;nbsp;操作是无状态的。&lt;/p&gt;
&lt;p&gt;这里所说的无状态是指任何客户都可以使用某个Service的任何实例。&lt;/p&gt;</description><pubDate>Thu, 28 Jul 2011 00:44:54 GMT</pubDate><guid isPermaLink="true">http://www.iduu.net:80/develop/TDD-%E8%BD%AF%E4%BB%B6%E4%B8%AD%E6%89%80%E8%A1%A8%E7%A4%BA%E7%9A%84%E6%A8%A1%E5%9E%8B</guid></item><item><title>提高代码可测试性的准则</title><link>http://www.iduu.net:80/develop/%E6%8F%90%E9%AB%98%E4%BB%A3%E7%A0%81%E5%8F%AF%E6%B5%8B%E8%AF%95%E6%80%A7%E7%9A%84%E5%87%86%E5%88%99</link><description>&lt;p&gt;在用&lt;a href="/Tags/%E6%B5%8B%E8%AF%95%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91" target="_blank"&gt;测试驱动开发&lt;/a&gt;的方式写代码时，我们实际上是在做设计，而这些设计会直接影响代码将来的友好程度。在编写代码前先写测试能够提高代码的可测试性。但如果遵循下列的设计准则，将能解决代码不可测试的问题。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;多用组合少用继承&lt;/li&gt;
&lt;li&gt;避免使用static关键字，以及Singleton模式&lt;/li&gt;
&lt;li&gt;隔离依赖（Isolate dependencies）&lt;/li&gt;
&lt;li&gt;注入依赖（Inject dependencies）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;尽量使用组合而非继承&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如何从各个独立的功能构建出复杂的对象，对代码的可测试性影响很大。在面向对象的语言中，继承以及组合都可以实现此功能。&lt;/p&gt;
&lt;p&gt;继承是静态的、类级别上的责任的划分，在代码编译后不能改变。继承在设计的可测试性、可维护性、以及复杂性方面都有负面影响。&lt;/p&gt;
&lt;p&gt;组合是动态的对象级别的责任划分，可以在运行时，替换不同的对象实现不同的职责。组合能够提高可测试性，适应性和可维护性，这些优点远大于几行代码带来的麻烦。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;避免使用static关键字，以及Singleton模式&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;静态方法和Singleton模式会影响可测试性，这取决于待测试代码于静态方法或Singleton模式的纠葛程度。在测试中用测试替身替换静态方法可能及其困难。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;隔离依赖（Isolate dependencies）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;隔离依赖对可测试性及可维护性至关重要，为了能够方便的用测试替身替换依赖，隔离依赖使其更容易替换非常关键。有几种方法可以解决这个问题&lt;/p&gt;
&lt;p&gt;1.把静态方法问访问移至成员方法&lt;/p&gt;
&lt;p&gt;2.使用&amp;ldquo;接缝&amp;rdquo;技术&lt;/p&gt;
&lt;p&gt;接缝(seams):不用修改直接影响行为的代码就能改变系统行为的那个点。换言之，在测试期间可以在某个点用一段代码替换另一段代码，而无需修改待测试代码，这个点就是接缝。&lt;/p&gt;
&lt;p&gt;public class OrderProcessor{&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void process(Order order){&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PrincingService service = getPricingService();&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected PricingServiece getPricingService(){&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return PrincingService.getInstance();&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;上例中得getPricingService()方法实际就是接缝。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注入依赖（Inject dependencies）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;依赖注入（DI）这种代码组织方式可以减少直接依赖，将其变为间接依赖。或者说把getter变成setter。&lt;/p&gt;
&lt;p&gt;public class OrderProcessor{&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void process(Order order){&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PrincingService service = getPricingService();&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected PricingServiece getPricingService(){&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return PrincingService.getInstance();&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;这段代码展示了如歌隔离依赖，方便以后替换PrincingService实现。这里的getter是指getPrincingService的默认实现，使用PrincingService的静态方法主动获取PrincingService的实例。OrderProcessor类与PrincingService存在耦合关系。使用注入依赖可以解决这个问题。让OrderProcessor明确表示&amp;ldquo;我需要一个PrincingServie，使用我之前必须先满足我得需要&amp;rdquo;。具体实现如下：&lt;/p&gt;
&lt;p&gt;public class OrderProcessor{&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private PrincingService&amp;nbsp; _princingService;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public OrderProcessor(PrincingService princingService){&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _princingService = princingService;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;虽然依赖注入是代码的测试性大有改观，但也要付出一定的代价。必须把所有的依赖传递给各个组件。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description><pubDate>Mon, 25 Jul 2011 09:52:22 GMT</pubDate><guid isPermaLink="true">http://www.iduu.net:80/develop/%E6%8F%90%E9%AB%98%E4%BB%A3%E7%A0%81%E5%8F%AF%E6%B5%8B%E8%AF%95%E6%80%A7%E7%9A%84%E5%87%86%E5%88%99</guid></item><item><title>SRP:单一职责原则</title><link>http://www.iduu.net:80/develop/srp-%E5%8D%95%E4%B8%80%E8%81%8C%E8%B4%A3%E5%8E%9F%E5%88%99</link><description>SRP:单一职责原则</description><pubDate>Sat, 16 Jul 2011 17:38:12 GMT</pubDate><guid isPermaLink="true">http://www.iduu.net:80/develop/srp-%E5%8D%95%E4%B8%80%E8%81%8C%E8%B4%A3%E5%8E%9F%E5%88%99</guid></item><item><title>测试夹具（Fixture）介绍</title><link>http://www.iduu.net:80/develop/Fixture</link><description>&lt;p&gt;什么事测试夹具&lt;/p&gt;
&lt;p&gt;测试夹具是测试的上下文。是测试类中所有测试方法的共有初始条件。从本质上来说，夹具是整个运行时的状态，而并非仅只测试类的成员变量，或相关对象内部状态。&lt;/p&gt;
&lt;p&gt;为什么需要夹具？因为夹具能够帮助我们消除重复，使测试更加紧凑。&lt;/p&gt;
&lt;p&gt;追求优良的设计是重视夹具的备份原因。夹具把多个测试共享的状态移至一处，有效的消除了重复。但是我们也需要在消除重复和测试的可读性之间做出平衡。&lt;/p&gt;
&lt;p&gt;测试方法只关心真正要测的东西，同时要避免其他任何干扰。通过夹具将相关的设置功能封装，可以简化验证逻辑，使测试更加紧凑。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description><pubDate>Fri, 15 Jul 2011 16:12:01 GMT</pubDate><guid isPermaLink="true">http://www.iduu.net:80/develop/Fixture</guid></item><item><title>测试驱动开发（TDD）中选择测试的方法</title><link>http://www.iduu.net:80/develop/tddxuanzeceshi</link><description>&lt;p&gt;在编写测试的时候，首先需要选择一个测试来进行编码，这时我们需要从一下几个方面做出权衡。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;细节和整体&lt;/li&gt;
&lt;li&gt;探索未知与轻车熟路&lt;/li&gt;
&lt;li&gt;最大限度的获取价值与摘取现成的果实&lt;/li&gt;
&lt;li&gt;走通基本功能路劲与先处理出错情况&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;细节和整体&lt;/p&gt;
&lt;p&gt;树的遍历方法有广度优先和深度优先。在实现功能的时候，也可以分为细节优先和整体优先两种方法。两种方法各有优缺点。细节优先有利于降低风险，例如&amp;ldquo;我们能够对用户提交的图片进行模式识别吗？&amp;rdquo;，从整体考虑，处理模式识别会耽搁整体的进度。整体优先的优势是能快速的验证总体设计，但是会推迟细节方面的工作进度，&lt;/p&gt;
&lt;p&gt;不确定和熟悉&lt;/p&gt;
&lt;p&gt;减少不确定性是我们选择测试时要考虑的因素之一。首先处理不确定的内容能够有效的降低技术风险。&lt;/p&gt;
&lt;p&gt;高价值和现成的果实&lt;/p&gt;
&lt;p&gt;理想情况下，我们应该挑选那些工作量少，价值大的测试首先完成。&lt;/p&gt;
&lt;p&gt;基本功能与出错情况&lt;/p&gt;
&lt;p&gt;通常，应该先选择基本功能，然后处理出错情况。&lt;/p&gt;</description><pubDate>Fri, 15 Jul 2011 15:56:45 GMT</pubDate><guid isPermaLink="true">http://www.iduu.net:80/develop/tddxuanzeceshi</guid></item></channel></rss>
