设计模式概论

设计模式(Design pattern)是一套被反复使用,多数人知晓的,经过分类编目的,代码设计经验的总结。使用设计模式是为了可重用代码,让代码更容易被他人理解,保证代码可靠性。毫无疑问,设计模式于已于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。

模式的经典定义:每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心,通过这种方式,我们可以无数次地重用那些已有的解决方案,无需再重复相同的工作。即模式是在特定环境中解决问题的一种方案。

设计模式目的

其目的就是一方面教你如何利用真实可靠的设计来组织代码的模板。简单地说,就是从前辈们在程序设计过程中总结,抽象出来的能用优秀经验。主要目的一方面是为了增加程序的灵活性,可重用性。另一方面也有助于程序设计的标准化和提高系统开发进度。

也有人忠告:不要过于注重程序的"设计模式"。有时候,写一个简单的算法,要比引入某种模式更容易。在多数情况下,程序代码应是简单易懂,基于清洁式也能看懂。不过呢在大项目或者框架中,没有设计模式来组织代码,别人是不易理解的。

一个软件设计模式也仅仅只是一个引导。它必须根据程序设计语言和你的应用程序的特点和要求而特别的设计。

设计模式的四个基本要素

设计模式使人们可以更加简单方便地复用成功的设计和体系结构。将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。

所有的设计模式都有一些常用的特性:一个标识(a pattern name), 一个问题陈述(a problem statement)和 一个解决方案(a solution), 效果(consequences)

模式名称(pattern name): 描述模式的问题,解决方案和效果
一个设计模式的标识(模式名称)是重要的,因为它会让其他的程序员不用进行太深入的学习就能立刻理解你的代码的目的(至少通过个标识程序会很熟悉这个模式)。没有这个模式名,我们便无法与其他人交流设计思想及设计结果。

问题(problem): 描述是用来说明这个模式的应用的领域。
描述了应该在何时使用模式。它解释了设计问题和问题存在的前因后果,它可能描述了特定的设计问题,如怎样用对象表示算法等。也可能描述了导致不灵活设计的类或对象结构。有时候,问题部分会包括使用模式必须满足的一系列先决条件。

解决方案(solution):描述了这个模型的执行。
描述了设计的组成成分,它们之间的相系关系及各自的职责和协作方式。因为模式就像一个模板,可应用于多种不同场合,所以解决方案并不描述一个特定而具体的设计或实现,而是描述设计问题的抽象描述和怎样用一个具有一般意义的元素组合(类或对象组合)来解决这个问题。

效果(consequences)
描述了模式应用的效果及使用模式应权衡的问题。尽管我们描述设计决策时,并不总提到模式效果,但它们对于评价设计选择和理解使用模式的代价及好处具有重要意义。软件效果大多关注对时间和空间的衡量,它们也表述了语言和实现问题。因为复用是面向对象设计的要素之一,所以模式效果包括它对系统的灵活性,扩充性或可移植性的影响,显式地列出这些效果对理解秋评价这些模式很有帮助。一个好的设计模式的论述应该覆盖使用这个模型的优点和缺点。

一个模式是解决特定问题的有效方法。一个设计模式不是一个库(能在你的项目中直接包含和使用的代码库) 而是一个用来组织你的代码的模板(Java bean)。实事上,一个代码库和一个设计模式在应用上是有很多不同的。

比如,你从店铺晨面买的一件衬衫是一个代码库,它的颜色,样式和大小都由设计师和厂商决定。但它满足了你的需求。然而,如果店里面没有什么衣服适合你,那你就能自己创建自己的衬衫(设计它的形状,选择布料,然后裁缝在一起)。但是如果你不是一个裁缝,你可能会发现自己很容易的去找一个合适的模式然后按着这个模式去设计自己的衬衫。使用一个模型,你可以在更少时间内得到一个熟练设计的衬衫。

回到讨论软件上来,一个数据提取层或者一个CMS(content management system) 就是一个库 -- 它是先前设计好而且已经编码好了的。如果它能准确的满足你的需要那它就是一个好的选择。但如果你正在读这本书《设计模式》,可能你会发现 库存的(原有的)解决方案并不是总是对你有效。至今你知道什么是你所要的,而且你能够实现它,你仅仅需要一个模型来引导你。

最后一个想法:就象一个裁缝模型,一个设计本身而言是没有什么用处的。毕竟,你不可能穿一个服装模型--它仅仅是由很薄的纸拼凑起来的。类似的,一个软件设计模型也仅仅只是一个引导。它必须根据程序设计语言和你的应用程序的特点和要求而特别的设计。

设计分类

1)根据其目的(模式是用来做什么的) 可分为创建型(Creational), 结构型(Structural) 和 行为型(Behavioral)三种:

  • 创建型模式:主要用于创建对象。
  • 结构型模式:主要用于处理类或对象的组合
  • 行为型模式:主要用于描述对类或对象怎样交互和怎样分配职责。

2) 根据范围,即模式主要是用于处理类之间关系还是处理对象之间的关系,可分为类模式和对象模式两种:

  • 处理类和子类之间的关系,这些关系通过继承建立,在编译时刻就被确定下来,同属于静态的。
  • 对象模式:处理对象间的关系,这些关系在运行时刻变化,更具有动态性。

设计模式六大原则

设计模式的核心原则是:“开-闭”原则(Open - ClosedPrinciple 缩写:OCP):对扩展开放,对修改关闭

意思是,在一个系统中,对于扩展是开放的,对于修改是关闭的,一个好的系统是在不修改源代码的情况下,可以扩展你的功能。。而实现开闭原则的关键就是抽象化

通过扩展已有软件系统,可以提供新的行为,以满足对软件的新的需求,使变化有的软件有一定的适应性和灵活性。已有软件模块,特别是最重要的抽象层模块不能再修改,这使变化中的软件系统有一定的稳定性和延续性。

在"开-闭"原则中,不允许修改的是抽象的类或者接口,允许扩展的是具体折实现类,抽象类和接口在“开-闭”原则中扮演着极其重要的角色。。即要预知可能变化的需求。又预见所有可能已知的扩展。。所以在这里“抽象化”是关键!!!

可变性的封闭原则:找到系统的可变因素,将它封装起来。。 这是对“开-闭”原则最好的实现。。不要把你的可变因素放在多个类中,或者散落在程序的各个角落。。你应该将可变的因素,封装起来。。并且切忌不要把所用的可变因素封套在一起。。最好的解决办法是,分块封套你的可变因素!! 避免超大类,超长类,超长方法的出现!! 给你的程序增加艺术气息,将程序艺术化是我们的目标!!

里氏代换原则:任何基类可以出现的地方,子类也可以出现 Liskov Substitution Principle(里氏代换原则):子类能够必须能够替换基类能够从出现的地方。子类也能在基类的基础上新增行为。这讲的是基类和子类的关系,只有这种关系存在时,里氏代换原则才存在。正方形是长方形是理解里氏代换原则的经典例子。

依赖倒转原则:要依赖抽象,而不要依赖具体的实现 依赖倒置(Dependence Inversion Principle)原则讲的是:要依赖于抽象,不要依赖于具体。简单的说,依赖倒置原则要求客户端客户端依赖于抽象耦合。原则表述:

  • 抽象不应当依赖于细节;细节应当依赖于抽象;
  • 要针对接口编辑,不针对实现编程;

如果说开闭原则是目标,依赖倒转原则是到达“开闭”原则的手段。。如果要达到最好的“开闭”原则,就要尽量的遵守依赖倒转原则。。可以说依赖倒转原则是对“抽象化”的最好规范!! 我个人感觉,依赖倒转原则也是里代换原则的补充。。 你理解了里氏代换原则,再来理解依赖倒转原则应该是很容易的。。

合成/聚合复用原则(CARP):要尽量使用合成/聚合原则,而不是继承关系达到软件复用的目的 合成/聚合复用原则(Composite/Aggregate ReusePrinciple 或 CARP)经常又叫做合成复用原则(Composite ReusePrinciple 或CRP),就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新对象通过向这些对象的委派达到复用已有功能的目的。简而言之,要尽量使用合成/聚合,尽量不要使用继承。

迪类特法则:系统中的类,尽量不要与其他类互相作用,减少类之间的耦合度 迪类特法则(Law of Demeter或简写LoD)又叫最少知识原则(Least Knowledge Principle或简写为LKP),也就是说,一个对象应当对其他对象有尽可能少的了解。

其它表述:只与你直接的朋友们通信,不要跟“陌生人”说话。一个类应该对自己需要耦合或调用的类知道得最少, 你(被耦合或调用的类)的内部是如何复杂都和我没关系,那是你的事情,我就知道你提供的public方法,我就调用这么多,其他的一概不关心。

迪米特法则与设计模式Facade模式, Mediator模式使民无知

系统中的类,尽量不要与其他类互相作用,减少类之间的耦合度,因为在你的系统中,扩展的时候,你可能需要修改这些类,而类与类之间的关系,决定了修改的复杂度,相互作用越多,则修改难度就越大,反之,如果相互作用的越小,则修改起为的难度就越小。。如果A类依赖B类,则B类依赖C类,当你在个性A类的时候, 你要考虑B类是否会受到影响,而B类的影响是否又会影响到C类..如果此时C类再依赖D类的话,呵呵,我想这样的修改有的受了。。

接口隔离法则:这个法则与迪米特法则是相通的 接口隔离原则(Interface Segregation Principle)讲的是:使用多个专门的接口比使用单一的总接口总要好。换而言之,从一个客户类的角度来讲:一个类对另外一个类的依赖应当是建立在最小接口上的。过于臃肿的接口是对接口的污染。不应该强迫客户依赖于它们不用的方法。

迪米特法则是目的,而接口隔离法则是对迪米特法则的规范。。为了做到尽可能小的耦合性,我们需要使用接口规范类,用接口来约束类。要达到迪米特法则的要求,最好就是实现接口隔离法则,实现接口隔离法则,你也就满足了迪米特法则。。。

results matching ""

    No results matching ""