(2)类的使用者须依赖类共有接口,但类不能
(3)尽量减少类的协议
(4)实所有类都理解的最基本公有口[例如,拷贝*作(拷贝和浅拷贝)、等性判断、正确输出内
(5)不要把实现细(例如放置用代码的私有函数)放
如果类的两个方法有一公共代码,那就可以创建一个防止这些
(6)不要以用户法使用或不感兴趣的东西扰
(7)之间应该零耦合,或者只有出耦合关系。也即,个类要么同另一个毫无关系,要么只使
(8)类应该只表示一个
包中所类对于同一类性质的变化应是共同封闭的。一个变化对一个包影响,则
(9)把相关的数据和行为
设计者当留意那些通过get类*作从别的对象获取数据的对。这种类型的行为暗
(10)把不相关信息放在一个类中(也即:互
朝着稳定的方向进
11)确保你为之模的抽象念是类,而不只是
(12)在水平方向上尽可统一地分布系功能,也即:按照设计,顶层
(13)
规划一个接口而不是实现
(14)对公共接口中定义了量访问方法的类加小心。大量访问方法意味着相关
(15)对包太多互不沟通的行为的
这个题的另一表现是在的应用程序中类的公有接口中创建了很多
(16)在由同用户界面交互面向对象模型构成应用程序中,型不应该依赖于界
(17)可能地按照现实世界建模(我常常为了遵守系统功能布原则、避免全能类则以及集中放置相关数据
(18)从你的设计中去除不
一般来说,们会把这个类降级
(19)去除系统
系统外类的特点是,抽象看它们只往系统域发送消息但并不接受系统领
(20)要把*作变成类。质疑任何名字是动或者派生自动词的类,特别是有一个有意义行为类。虑一下那个有意义的行为是否
(21)我们在创建应用程序的析模型时常常引入理类。在设计段,我们常会发现很
(22)尽量减少类的协作
一个类用到的其他类的数目应
(23)尽量少类和协作者之间传递
(24)尽量减少类和协者之间的协作量,也即:减少类和协作者之间
(25)尽量减少类扇出,也即:少类定义的消息数和发
(26)如果类包含另一个类的象,那么包含类应给被包含的对发送消息。也即:包
(27)类中定义的多数方法都当在大多数时间里使
(28)类含的对象数目不应当超过开发者短期记的容量。这个数目常常是当类包多于6个数据成员,可把逻辑相关的数据成员划分为一
(29)让系功能在窄而深的继承体
(30)实现语义约束时,最好根据类定义实现。这常常会导致类泛滥灾,在这种情况,束应当在类的行为中实现,通
面向对象程序设计原则——单一职责原则
面向对象程序设计原则——单一
华迪教育http://www.hwadedu.com/
华迪信息http://www.hwadee.com/
单一职责原则的英文名称
其核思想为:一类,最好只做件事,只有一个引起它的变化。单一职原可以看做是低耦合、高内聚在面象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引变化原因。职责过多,可能引它变化的原因就越多,这将导致职依赖,相互之间就产影响,从而大大损伤其内聚性和耦合度。通常意义下的单责,就是只有一种单一功能,不要为实现过多
专注,是个人优良的品质;同样的,单一也一个类的优良设计。交杂不清职责将使得代码起来别别扭牵一发而动全身,有
这个计则备受争议。这个原则存在争议之在哪里呢,就是对职责的定,什么是类的职,及怎么划分类的职责。我们先
只要做过,肯定要接触到用户、机构、角色管理这些,基本上使用的都是RBAC(基于角色的访问控制)模型,确实是很好的一个解决办法。我们要讲的是用户管理、改用户的信息、加机构(一人属于多个机)、增加角色等,用户有这么的信息和行为要维,我们就把这些写到一个接口中,都是用户管
图1 用户信息维
太简单的类了,我相信,使是一个初级的程序员也可以看出这个口计得有问题,用户的属性(Property)和用户的行为(Behavior)没有分开,这是一个严重错误~非常正确,这个接口确实计得一团糟,应该把户的信息抽成一个BO(Bussiness Object,业务对象),把行为抽取成BIZ(Business Logic,业务逻
IUserBoIUserBiz
IUser
UserInfo
图2 职责划分后
重新拆封成两个接
集和反馈用的属性信息;IUserBiz负用户的行为,完成用户信息的维护和变更。各位可要说,这个与我实际工作中用到User是有差别的呀~别着急,我们先来看一看分拆成两个口怎么使用。OK,我们现在是面向口编程,产生了个UserInfo象之后,当然可以把它当IUserBO接使用。当然,也可以当IUserBiz接口使用,这要看你在什么地方使用了。要获得用户信息,是IUserBO的实现类;要是希望维护用户的息,就把它当
代码清单1-1 分清职责后的
.......
IUserBiz userInfo =new UserInfo();
//认为它是一个纯粹
IUserBO userBO = (IUserBO)userInfo;
userBO.setPassword("abc");
//我要执行作了,我就认为是一个
IUserBiz userBiz = (IUserBiz)userInfo;
userBiz.deleteUser();
.......
确以如此,问题也解决了,但是我来回想一下我们刚的动作,为什么要把一个接口拆分成两个呢,实,在实际的使用中,我们倾向于用两个不
IUserBizIUserBo
UserBoUserBiz
图1-3 项目中经常采用的SRP类图
以上们一个接口拆分成两个接口的动作,就是依赖了单一职责原则,什么是单一职责则,单一职责原则的定义是:
更多息
Java面向对象程序设计的基本原则
在软件件系统中,一模块设计得好不好的最主要、最重要的,就是该模块在多大程度自己的内部数据和其他与实现有关的细节隐藏起来。一个设计好的模块可以将它所的实现细节隐藏来,彻底将提供给外界API和自己的实现分隔开来。这样一来,模模块之间就可以仅仅通过彼此的API
OO设计根本的指原则是提高维护性和可复用性。
1. 开闭原则
一个软件实应该对扩展开放,
在设一模块的时候,就当使这个模可以在不被修改的前提被扩展。换言之,就当可以在不必修改源代
如何做到既不修改,又可
解决问的关键抽象化:在Java语言里,可以一个或多个抽象Java类或Java接口,规定出所有的具体类必须提供的法特征作为系统设计的抽象层。个抽象预见了所有可能扩展,因此,在任何扩展情况下都
同时,于从抽象层导出一或多个新的具体可以改变系统的行为,因此系
开闭原实际上是对“对可变的封闭原则“:找一个系统的可因素,将之封装起
1) 一可变性不应当散落在代码的很角落里,而应当被封装一个对象里面。同一可变性的不同表象意昧着
继承当被看作是封装化的方法,而应当被认为是从一般的对象
2) 一可变性不应当与另一种可变混合在一起。(所有类图继承结构一般不会过两层,不然就意昧着将
开闭原则是总的则,其它几条是开闭原则
2. 依赖倒转原则
依赖倒转原则讲是:要依赖于抽象,不
开闭原则是目标,而达到这一目标的手段是
抽象层次包含的是应用统的商务逻和宏观的、对整个系统来
是必性体现;而具体层次则含有一些次要的实现有关的算法和逻辑,以及术性的决定,带相当的偶然性选择。具体层次的代
抽象次有一个应用系统最重要的宏观商逻辑,是做战略判断和决的地方,那么抽层就应当是较为稳定的,应当
在很情下,一个Java程序需要引用一对象。这个时候,如果这个对有一个抽象类型的,当使用这个抽象类型作为变量
一般而言,在创建个对象时,Java语言求使用new关键以及这个类本身。而旦这个象已经被创建出来,那么就可以灵活地使用这个对象的抽象类型来引用它。比如:List employees = new Vector();因,Java语言中建一对象过程是违背“开闭原则”以及依赖转原则的(因为先生成了具体的类型,再使用抽象的引用),虽在这个类被创建出来以后,可以通过多态使得户依于其抽象类型。由于这个问,设计式给出了多个建模式,特别是几个工厂模式,用于解决象创建过程中的依赖倒转问题。 工厂模式将建一个类的实的过程封起来,消费这个实例的客户端仅仅取得实例化的结果,以这个实例的抽象类型。当然,任何方都无法回避Java语言所要求的new关键字和直接调用具体类构造子的做法(这违背了里氏代换则)。简单工厂模式将这个反“开闭原则”和依赖倒转原则的做法封装到了个类里面,而工厂方式将这个违反原则的做法迟到了体工厂角色。通过适当的封装,工厂模式可以净化大部分的结构,而违反原则的法孤
联合使Java接Java抽象类:声明类型的工作由Java接承担,但是同时给出的还个Java抽象类,为这个接口给出一个缺省实现。如果一个具体接实现这个Java口的话,它就必自行实现所的接口;相反,果它继承自抽象类的话,它就可以省去一些不必方法,因为它可以从抽象类中自动到这些
依赖倒转的缺点:
1) 因为赖倒转的缘故,对象的创建可能要使用对工厂,以避免对具体类的直接引用,原则的使用还会导致大
2) 依赖转原则假定所有的具体类是会变化的,也不总是正确的。有一些具体类可能当稳定、不会发生变,消这个具体类实例的客户端完全可以
3. 里氏代换原则
任何基类可出现的地方,子类一
开闭原的关键步骤是抽象化。而类与子类的继承关系是抽象化的具体现,里氏代换原则是对
4. 合成/聚合
要尽量使用合成/聚合,而不是继承关系达
合成/聚合则要求我们首先考虑合成/聚合关系,氏代换原则要求在使用继承时,必确定这个继承关系符一定条件(继承是用来封装变化的;
合成/聚原则就是在一个新的对象里面用一些已有的对象,使成为新对象的一部分;新的对象通过向这些对象
5. 迪米特原则
一个件体应当尽可能少的其他实体发相互作用。模块之间的交要少。这样做的结果
一个对象应对其他对象有尽可
迪米特原则的具
1) 优考虑将一个类设置成不变类。不变类易于设计、实现
一个象与界的通信大体上分成两种,一种是改变个对象的状态,另一种是不改变个对象的状态的。如一对象的内部状态根本就是不可能改
当涉任何个类的时候,都首先考虑个类的状态是需要改变。即便一个类必须是可变,在给它的属性设置值方的时候,也要保持吝啬的态度。除
2) 尽量降低一个类的
3) 谨使用Serializable,旦将一个类设置成Serializable,就能在新版本中修改这个类的内部
4) 尽量降低成员的访
6. 接口隔离原则
应当为户端提供尽可能小的单接口,而不要提供的总接口。也是使用多个专门的接
接口离原则米特都是对一个软件实体与其的软件实体的通信制。迪米特原则要求尽可能地限制通信的宽和深度,接品隔离原则要通信的度尽可能窄。这样做的结果使一个软件系
一个口相当本中的一种角色,而此角色一个舞台上由哪个演员来演则相当于接口的实现。因此,个接口应当简单地代表个角色,而不是多个角色。如果系统涉及到多个
定制务:如户端仅仅需要某一些方法的,那么就应当向客端提供这些需要的方法,而不要提供不需的方法。(向客户端提供public接口是一种承诺,没有必要做出不必
面向对象程序设计与原则
面向对象的程序
1.需求分析
2(总体设计
3(详细
4(实现阶段
一、需求
以用例图为主,到类分析图为止。类是源码的来源。用的功能用序列图表示。用例状态可
照不同用户画出不同用例图。按照不同理位置画部署图;按照不同类型户程序行分类,得到组件图。从序列图得协作图,并且行简单类分析,得到类
二、总体设计
为用户所见的统计算
每一个例的完整序列图,包括主功能,备用功,异常件,误输入与误处理等序列图集,一个分支一个序图。用一个活动图归并部序列,遇到支用菱形框,得用例的完整功能。细化用例图,比较每一个例的活动图,得到相同的分,分解成包含用例;对于复杂功能的用,分解多个包含用例。对有些功能进行块化扩展,
序列图得到协作图,进行简单分析,特别实体类。增类:界面类,事务管理类。 画出统状态图(有活动表达式),对重要的画出类的状态,从中得到新的属性与操。 对增加的类重新画
细化状态图。
态图为主,应用类图是重心,画全部用户细化用例图,说明其系统接口。 画出系统总体设计,根据应用图与顺序活动图。
程序的内部结构
类图为主,重
从类图得到程序的构,从顺活动图得
重画有控制类的序图、
.用协作图将操作函化,
.给出类状态图的活动达式。状态的事件是序图的
转换事件的实现,此是
分解活动图,根据某一个操。与活动表达不同。 应用
子系统的划分:类图,活动图(模块图),件,部署图。
建立程序设
四、实现阶段
建立并发视图。
组件图:可执行
部署图:进程,设
软件测试
产品阶段
最基本的设计原有5条,分是:单一职
口隔离原则和Liskov替换原则。
SRP,一职责原则,一个类应该有且只一个改变理由。 OCP,开放封闭原则,你应能够用修原有类就能扩展一个类的行为。 LSP,Liskov替换原则,派生类要与其类自相容。 DIP,依
ISP,接口隔离原则,客户只
REP,重用发布等价原则,重用的粒就是发布的粒。 CCP,共同封闭原,包中
CRP,共同重用则,一包中的
ADP,无环依赖原则,在包的依赖关系图中不许存在环。 SDP,稳依赖原则,朝着稳定的方进行依赖。 SAP,稳定
单一职责原
对于单一职责原则,其核心思想为:一个类,最好只做一件事,只有个引起它的变化。单一职责原可以看做低耦合、高内聚面向对象原则上的引申,将职责义为引起变化的原因,以提内聚性来减少引起变化的原因。职责多,可能引它变化的原因就多,这将导致职责依赖,互之间就产生影响,从大大损伤其内聚性和耦合度。通常意义下的职责,就是指只有一种单一功能,不要为实现过多的能点,以证实体只有一个引起它变化的原因。专注,是一人优良的质;同样的,单一也是一个类的优良设计。交杂不的职责将使得代起特别别扭牵一发而动全身,有失美感和必然导致丑陋的系统错
开放封闭原则
对开放封闭原则,它是面向对象所原则的核心,软计到底追求的目标就是封变化、
放封闭则,其核心思想是:软件实体应是可扩展的,不可改的。也就是,对扩展放,对
1、对扩开放,意味着有新的需求或变时,可以现有代码进扩展,以适应新的情况。 2、对修封闭,意味着类一旦设计完成,就可以立完成其工作,而不要对其进行任何尝试修改。实现开开放封闭
具体编程,因抽象相对稳定。让类依赖于固定的抽象,所以改是封闭的;而通过面向对象的承和多态机制,可以实现对抽象类继承,过覆写方法 来改变有行为,实现新的拓展方法,所以就是的。“需求总是变化”有不变的软件,所以就需要用封闭开原则来闭变化满足需求,同时还能
依赖倒置原则
对于依倒置原则,其核心思想是:依赖于抽象。具体言就是层模块不依赖于层模块,二者都同依赖于抽象;象不赖于具,具体依赖于抽象。我们 知道,依赖一定会于类与类、模块与块之间。当两个模块之间存在紧的耦合系时,最好的方法就是分
高层模块用接口,而底层模块实现口的定义,以此来有控制耦合关系,达到依于象的计目标。抽象的稳定性决定了系的稳定性,因抽象是不变的,依赖
依赖于抽象是一个通用的原则,而某些时依赖于细节则是在难的,必须权衡在抽象和具体之间取舍,方法是一层不变的。依
接口隔离原则
对于接口隔离原则,其核思想是:使用多个小的专门的接口,而不要使用个大的总接。具体而言,接口隔原则体现在:口应该是内的,应该避免“胖”接。一个类对另外一个类的依赖应该建在最的接口上,不要强迫依赖不用的方,这是一种接口污染。接口有地将细节和抽象离,体现了对抽编程的一切好处,口隔离强调接口的单一性。而胖口存在明显的弊端,会导致实现类型必须完全实现接口的所有方法、属性等;而某些时候,现类型并非需要所有的接口定,在设计上这是“浪”,而且在实上这会带来潜的问题,对胖接口的修将导致一连串的客户端程序要修,有时候这一种灾难。在这种况下,将胖接口分解为多个特点的定制化方法,使得客户端仅仅依赖们的际调用的方法,从而解除了客户端不会依赖于它们用的方法。分离的手段主要以下
1、委托分离,通过增一个新的类来托客户的请求,隔客户
2、多重继承离,通过接多继承来实客户
Liskov替换原则
对于Liskov替换原则,其核心思想是:子类须够替换基类。这一思想现为对继承机制的约束规范,只子类够替换类时,才能保证系统在运行期内识别子类,这是继承复用的基础。在类和子类的具体行为中,必须严把握承层次中的关系和特征,
同时,一约束反过来则是不成立的,子类可以换基类,但是类不一定替换子类。Liskov替换原则,主着眼于对抽象和多态建在继承基础上,此只有遵循了Liskov替换原则,才能保证继承复用是地。实现的方法是面向接编程:将公共部分抽象为基类接口或抽象
同样的职责。Liskov替换原是关于继承制
Liskov替换原则能够保系统具有良的拓展,同时实现基于多的抽象
1) Open-Close Principle(OCP),开-闭原则,讲的是设计要对扩展有好的支,而修改严格限制。这是最重要也是最为抽象的原则,基本上我们所说的Reusable Software
2) Liskov Substituition Principle(LSP),里氏代换原则,很严的原,规则“子类必须能够替换基类,否则不应当设计其子类。”也就是,子类只能去扩展基类,而是隐藏覆盖基类,如有这方
3) Dependence Inversion Principle(DIP),赖倒换原则,“设计依赖于抽象而不具体化”。换句话说就是设计的候我们要用抽象来思考,而是一上来就开始划分我需要哪些哪类,因为这是具体。这样做什么好处呢,人的思维身实际上就是很抽象的,我们分析问题的时候不是一下子就考虑到细,而是很抽象的将整个问题都构思出来,以面向抽象计是符合的思维的。另外这个原则会很好的支持OCP,面向抽的设计使我们够不必太多依赖于实现,这样扩展成为了可能,这则是另一篇文章《Design by Contract》
4) Interface Segregation Principle(ISP),“将大的接口打散成多小接口”,样做的好处很明显,
实际上对这些原则只是做了一个小结,如果有要更
5) Composition/Aggregation Reuse Principle(CARP),设计者首先当考虑复合/合,而不是继承(因
这个就所谓的“Favor Composition over Inheritance”,在实践
6) Law of Demeter or Least Knowlegde Principle(LoD or LKP),迪米特法则最少知识原则,这个
迪米特则。它讲的是“一个对象应当可能少的去解其他象”。也就是又一关于如
0808300034面向对象程序设计的基本原则和设计模式
目录
内容摘要 ……………………………………………………………(2) 1、面向对象的几个基本原则
1、 1向抽象原则………………………………………………(2) 1、 2—闭则…………………………………………………(4) 1、 3
1、 4高内聚—耦合原
2、几个
2、 1策略模式……………………………………………………(7) 2、 2中介者
2、 3模板方法
3、总结 …………………………………………………………… (18)
4、参考文献 ……………………………………………………… (19)
面向对象程序设计几个
内容摘要
本文重点绍了面向对象程序设计的几基本原 (面向抽原则、 开—闭原则、 多 组少用继承原则)和设计模式(策模式、中介者
关键词 :面向对
一个好的设计系往往是易维护、 易扩展、 易复用的, 面对象的本原则助于知道 如何使用面向对象语言写出易维护、 易扩、 易复用的程序代码, 设计模也正是从秀 的设计系统总结出的设计精髓, 并且充分体现了其基本原, 对提高程序员的设计能力 非常有帮助。 需要强调的一点是, 本文介绍的这原则、 及设计模式是在许多设计中结 出的指性则,并不是任何设计都必须要遵守的“法律”
1、面向对
1.1面向抽象原则
【核心思想】 :
所谓面向象编程, 是指当设计一个类时, 不让该面向具体的类, 是向象类或 者接口,即所设计类的重要数据抽象类或接口声明
例如,经有了一个 Circle 类,类创建的对象 circle 调用 getArea()
public class Circle {
double r;
Circle(double r) {
this.r=r;
}
public double getArea() {
return(3.14*r*r);
}
}
现在要计一个 Pillar 类 (类) , 该的对调用 getVolum()方
public class Pillar {
Geometry bottom;
double height;
Pillar (Circle bottom, double height) {
this.bottom=bottom; this.height=height;
}
public double getVolume() {
return bottom.getArea()*height;
}
}
上述 Pillar 类中, Bottom 是用具体类 Circle 声明的变量,如果涉及用户需求变化, 上面 Pillar 类的设没有什么不,但是在某个时候,用户希望 Pillar 类能创建出底是角 形的柱体。显然上述 Pillar 类法创建出这样的柱体,即上
现在重新来设 Pillar 类。首先,注意到柱体计算积的键上述计出底面积,一个 体在计算底面时不应该关系它的底怎样形的具体形, 应该只心这种图形是否具 有计算面积的方法。此,在设计 Pillar 类时不应当让它的底是某个具体类明的变
下面将面抽象重新设计 Pillar 。首先编一个抽象类 Geometry (或接口) ,该抽象 类(接口)中定
public abstract class Geometry { //如果使接口需
public abstract double getArea();
}
现在 Pillar 类的设计者可以面向 Geometry 类编写码,即 Pillar 类应当 Geometry 对 作为自的成员, 该成员可以调用 Geometry 类重写的 getArea()方法。 这样一来, Pillar 类就可以将计算底面积的
一下 Pillar 类的设计不再依赖体类,而面向 Geometry 类,即 Pillar 类中的 bottom 是用抽象类 Geometry 声明的变量,而不是具类声明的变量。重新设
public class Pillar {
Geometry bottom; //bottom是抽
double height;
Pillar (Geometry bottom,double height) {
this.bottom=bottom; this.height=height;
}
public double getVolume() {
return bottom.getArea()*height; //bottom可以调用子类重写的 getArea 方法 }
}
下列 Circle 和 Rectange 类都是 Geometry 的子类, 二者都必须
public class Circle extends Geometry {
double r;
Circle(double r) {
this.r=r;
}
public double getArea() {
return(3.14*r*r);
}
}
现在就可以用 Pillar 类建出具有矩底火
Application.java
public class Application{
public static void main(String args[]){
Pillar pillar;
Geometry bottom;
bottom=new Rectangle(12,22,100);
pillar =new Pillar (bottom,58); //pillar是具有矩形底的柱体
System.out.println(
bottom=new Circle(10);
pillar =new Pillar (bottom,58); //pillar是具有圆形底的柱体
System.out.println(
}
}
UML
:
UML
【小结】 :
结合上述实,通过面向抽象类设计 Pillar 类 ,使该 Pillar 类不在依赖具体类,因此 当系增加新 Geometry 的子类时,比如增加一 Triangle 子类,那么不需要修改 Pillar 类的任何代码,就可以
1.2开—闭原则
【核心思想】 :
所谓“开—原则(Open — Closed Principle) ” ,是让设计应当对扩展开放,对改关 闭。 给出一个设计时, 应当首先考虑到用户需求变化, 将应对用户化的部分设计为对 扩展开放, 而设的核心部分是经过精心
改关闭的,即不能因为户的
【实例分析】 :
下面的例子中, 准备设计一广告牌, 望设计的广告牌可展示
public interface Advertisement {
public void showAdvertisement();
public String getCorpName();
}
public class AdvertisementBoard {
public void show(Advertisement adver) {
System.out.println(
}
}
public class PhilipsCorp implements Advertisement { //PhilipsCorp实现 Avertisement 接 口
public void showAdvertisement(){
System.out.println(
System.out.println(
System.out.println(
}
public String getCorpName() {
return
}
}
public class LenovoCorp implements Advertisement { //LenovoCorp实现 Avertisement 接口
public void showAdvertisement(){
System.out.println(
System.out.println(
System.out.println(
}
public String getCorpName() {
return
}
}
public class Example {
public static void main(String args[]) {
AdvertisementBoard board = new AdvertisementBoard();
board.show(new PhilipsCorp());
board.show(new LenovoCorp());
}
}
运行结果图 1-2
在例题中,果再增加一个 Java 源文件(对展开) ,源文件有一个实 Advertisement 接口类 IBMCorp ,那么 AdvertisementBoard 类需要做任何修改(对 AdvertisementBoard 类
Board.show(new IBMCorp());
显示 IBM 公司的广告词。
如果将例题中的 Advertisement ,接口、 AdvertisementBoard 类以 LenovoCorp PhilipsCorp 类看作是一个小的开发架, 将题看做是用户序, 那么框架满 “开—闭原 则” , 该框架相对用户的需求就比较维护, 因为当用户程序需要使广告牌现实 IBMCorp 公司的广告词时,只需简地扩展架,即在框架中增加一个实现 Advertisement 接口的 IBMCorp 类,而无须修改框架中其
【小结】 :
如果一个程序计遵守了“开—闭原则” ,那么这个计定是易维的,因为在设计 中增加新的模时, 不必修改计中的心模块。 通常无法让设计的每个部分都遵守 “开— 则” ,甚至不应这样去做,应当把主要精力集中在对设计最有可能因需求变化而
当设计某些系统, 经常需要面向抽象来考虑系统的总体计, 要考具体类, 这样 就容易设计出足 “开—闭原则” 的系统。 在程序设好后, 首先对 abstract 类的修改关闭, 否则, 一旦修改 abstract 类, 将可能致它的所有子类都需要做出修改; 应当增加 abstract 类的子类 开放,即再增加新
1.3多用
【核心思想】 :
在设计, 人们希望系统的类之间尽量是低耦合的系, 而不希望是耦关。 即在 许多情况下需要开继承的缺,而需要组合的优
之所以倡多用组合, 少用继承, 是因在许多计中, 人们希望系类之尽量是 低耦合的关系, 不希望是强合关系。 即在许多
1、 4高
【核心思想】 :
如果类中的方法是一相关的行,则称该
高内聚便于类的维护,而低
低耦合是尽量不要让一个类含有太多的它类的实例的引, 避免修改系统的其中 部分会
【小结】 :
提倡高聚—低耦合原则原理类似于多用组合,少继承的原则, 一好设系统 往往是易维护、 易展、 易复的, 使用这些原
2. 几个
一个设计式是针对某一类问题的最佳决方案, 而且已经成功应用于许多系统的 中, 它解决了在某种特定情景中重复发的某个问题, 即一个设计模式是从许
2.1策略模式
【定义及思想】 :
策略模式是处算法的不同变体的一种成熟模式,策略式通接口封算法的标识, 即接口中定义一抽象方法, 实该接口类将重接口中的抽象方法。 策略模式把针对 一个算法识的一系列具体算法别封装在不同的类中, 使得各个的具体法可以相互替 换,并且
【结构】 :
2.1.1角色—策模式
策略 (Strategy):策略是一个接,该接口定义干个
具体策 (ConcreteStrategy):具体是现策略接口的类。具体略重写
上下文 (Context) :上下文是依赖于略接口的类,即下包有策略声明的变量。 上下提供一个方,该方法委托策
2.1.2策略模
策略模式 UML 类图 2-1
【结构描述
以下通过一个简单的问题描述策
在某种比中有若干个裁判, 每位裁判选手一个分, 选的最后得分是根据全体裁 判得分和计算出来的。请给出集中计算选手分的评分方案(策略) 。对于某此比, 可以从这几种方案中
针对上述问题,是策略
(1)策略
本问题中,策略接口的名字是 ComputableStrategy, 该接口规定的算标识,即抽
ComputableStrategy.java
public interface ComputableStrategy{
public abstract double computeScore(double [] a);
}
(2)具体策略
对于本问题,有三个具体策略:StrategyOne 、 StrategyTwo 和 StrategyThree 。
StrategyOne 类将 double computeScore (double []a)方实现为计算数组 a 的元的代 数平均值; StrategyTwo 类将 double computeScore (double []a)方法实现为计算数组 a 的元 的几何平均值; StrategyThree 类将 double computeScore(double []a) 方法实现为去掉组 a 的元中一个最大值和一个最小值,然后计算剩余元素的代平
StrategyOne 、 StrategyTwo 和 StrategyThree 类的代码如下:
public class StrategyOne implements ComputableStrategy{
public double computeScore(double [] a){
double score=0,sum=0;
for(int i=0;i
sum=sum+a[i];
}
score=sum/a.length;
return score;
}
}
public class StrategyTwo implements ComputableStrategy{
public double computeScore(double [] a){
double score=0,multi=1;
int n=a.length;
for(int i=0;i
multi=multi*a[i];
}
score=Math.pow(multi,1.0/n);
return score;
}
}
import java.util.Arrays;
public class StrategyThree implements ComputableStrategy{
public double computeScore(double [] a){
if(a.length<>
return 0;
double score=0,sum=0;
Arrays.sort(a);
for(int i=1;i
sum=sum+a[i];
}
score=sum/(a.length-2);
return score;
}
}
(3)上下文
上下文是 GymnasticsGame 类,该类包含策略明的变量,此变量可用于保具体策 略的引。另外, GymnasticsGame 类中含一个 double 型数组 a,a
GymnasticsGame.java
public class GymnasticsGame{
ComputableStrategy strategy;
public void setStrategy(ComputableStrategy strategy){
this.strategy=strategy;
}
public double getPersonScore(double [] a){
if(strategy!=null)
return strategy.computeScore(a);
else
return 0;
}
}
下面应程序中, Appication.java 使用了策略模中涉的类,应用程序在使用策略 模式时,需创建具体策略的实
Application.java
public class Application{
public static void main(String args[]){
GymnasticsGame game=new GymnasticsGame(); //上下文对象
game.setStrategy(new StrategyOne()); //上下文对象使用策略一
Person zhang=new Person();
zhang.setName(
double [] a={9.12,9.25,8.87,9.99,6.99,7.88};
Person li=new Person();
li.setName(
double [] b={9.15,9.26,8.97,9.89,6.97,7.89};
zhang.setScore(game.getPersonScore(a));
li.setScore(game.getPersonScore(b));
System.out.println(
System.out.printf(
System.out.printf(
game.setStrategy(new StrategyTwo()); //上下文对象使用策略二
zhang.setScore(game.getPersonScore(a));
li.setScore(game.getPersonScore(b));
System.out.println(
System.out.printf(
System.out.printf(
game.setStrategy(new StrategyThree()); //上下文对象使用策略三
zhang.setScore(game.getPersonScore(a));
li.setScore(game.getPersonScore(b));
System.out.println(
System.out.printf(
System.out.printf(
}
class Person{
String name;
double score;
public void setScore(double t){
score=t;
}
public void setName(String s){
name=s;
}
public double getScore(){
return score;
}
public String getName(){
return name;
} }
运行效果图 2-2
【适合使用策
(1) 一个类定义了多行为, 并这些行为在个
现,那么可以使用策略模避免在
(2) 程序不希望暴露杂的、 与法相关的数据
(3)需要使用
【优点及优势】 :
上下文 (Context)和
用某一个实现 Strategy 接口类的
策略模式满足“开 -闭则” 。当加新的具体略
下文就可以引用
策略模式采用的是组合法, 即将个类的某个
的类中,而该类仅仅依这些类
2.2中介者模式
【定义及思想】 :
中介者模式体现了上述则中“多组合少用继
样合理地使用组合。
中介者模式是封装一系的对象交互
作中介者的对象中, 中者使各对象需要显示地相
当系统中某个对象需要系统中另外个对象交互,只
【结构】 :
2.2.1角色—中介模式的
中介者 (Mediator):一个接,该口定义了用于
方法。
具体中介者 (ConcreteMediator ):是实中介
同事(ConcreteColleague )的用,并通过重写介接口
同事 (Colleague):一个接口,规定了具体同事需要实现的方法。
具体同事(ConcreteColleague) :实现同事接口类。具体同事需要包含具中介的引 用, 一个具体同事需要和其他
给它所包含
2.2.2策略模
策略模式 UML 类图 2-3
【结构描述
下面通过一个简单的问题描述中
古代相互交战的 A 、 B 、 C 三方,想通过一个中介者停之间战火。 A 方委托停者 转达的信息是:“要求 B 方归还曾夺的 100斤土豆、要 C 归还曾抢夺 20头牛” ; B 方委托调停者转达的信息是:“要求 A 还曾抢夺的 10只公鸡、要 C 方归还曾抢夺的 15匹马” ; C 委托调停转达的信息是:“要求 A 方归还抢夺的 300
针对上述问题,使中介
(1)同事:
本问题,同事接口是 Colleague ,定了具同事,即交战各方需要实
public interface Colleague{
public void giveMess(String [] mess);
public void receiverMess(String mess);
public void setName(String name);
public String getName();
}
(2)具体中介者:
本问题中,只需要一个具体中介者,并不需要一中介接口。具体中介者
public class ConcreteMediator{
ColleagueA colleagueA;
ColleagueB colleagueB;
ColleagueC colleagueC;
public void registerColleagueA(ColleagueA colleagueA){
this.colleagueA=colleagueA;
}
public void registerColleagueB(ColleagueB colleagueB){
this.colleagueB=colleagueB;
}
public void registerColleagueC(ColleagueC colleagueC){
this.colleagueC=colleagueC;
}
public void deliverMess(Colleague colleague,String [] mess){
if(colleague==colleagueA){
if(mess.length>=2){
colleagueB.receiverMess(colleague.getName()+mess[0]);
colleagueC.receiverMess(colleague.getName()+mess[1]);
}
}
else if(colleague==colleagueB){
if(mess.length>=2){
colleagueA.receiverMess(colleague.getName()+mess[0]);
colleagueC.receiverMess(colleague.getName()+mess[1]);
}
}
else if(colleague==colleagueC){
if(mess.length>=2){
colleagueA.receiverMess(colleague.getName()+mess[0]);
colleagueB.receiverMess(colleague.getName()+mess[1]);
}
}
}
}
(3)具体同事:
对于本
public class ColleagueA implements Colleague{
ConcreteMediator mediator; //中介者
String name;
ColleagueA(ConcreteMediator mediator){
this.mediator=mediator;
mediator.registerColleagueA(this);
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void giveMess(String [] mess){
mediator.deliverMess(this,mess);
}
public void receiverMess(String mess){
System.out.println(name+
System.out.println(
}
}
public class ColleagueB implements Colleague{
ConcreteMediator mediator; //中介者
String name;
ColleagueB(ConcreteMediator mediator){
this.mediator=mediator;
mediator.registerColleagueB(this);
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void giveMess(String [] mess){
mediator.deliverMess(this,mess);
}
public void receiverMess(String mess){
System.out.println(name+
System.out.println(
}
}
public class ColleagueC implements Colleague{
ConcreteMediator mediator; //中介者
String name;
ColleagueC(ConcreteMediator mediator){
this.mediator=mediator;
mediator.registerColleagueC(this);
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void giveMess(String [] mess){
mediator.deliverMess(this,mess);
}
public void receiverMess(String mess){
System.out.println(name+
System.out.println(
}
}
下列应程序中, Application.java 使用中者式中所涉及的类,运行效
public static void main(String args[]){
ConcreteMediator mediator=new ConcreteMediator();
ColleagueA colleagueA=new ColleagueA(mediator);
ColleagueB colleagueB=new ColleagueB(mediator);
ColleagueC colleagueC=new ColleagueC(mediator);
colleagueA.setName(
colleagueB.setName(
colleagueC.setName(
String [] messA={
String [] messB={
String [] messC={
} }
运行效果图 2-4
【适合使用策
系统中许多对象以复杂的方式互, 所致的赖关系使系统以理解
【优点及优势】 :
可以避免许多的对象为了之间的信而相互显引, 否则不仅系统于维
可以通过介者将原本分布于多个对象之间交互行为中在一起。 当这对之需 要改变之间的通信行为时,只需使用一具体中介者即可,
具体中介者使得各个具体事完全解耦, 修改任何一具体
具体中介者集中了同事之间是何交互的细节, 使得系统比清楚
当一些对象想相互通信, 但无法相互含对的引用, 那使用中
2.3模板方法模式
【定义及思想】 :
模板方法模式体现了述“高内”原则,
模板方法是关怎样将若干个方法集成到一个方法中, 便形一个决问题的法骨 架。 模板方模式的关键是在个抽象类中定义一个法的骨, 即若干个方法集到一 个方法中, 并称该方法为一个模板法, 或简称为模板。 板方法所调用的其他方法通常为 抽象方法, 些抽象方法相当于算法骨架中
【结构】 :
2.3.1模板
抽象模板 (Abstract Template):抽象模板是一抽象类。 抽模板定义了若干个法以 表示个算法的各个步骤,这些方中有抽象方法也有 非抽象方法,其 中的抽象方称作原语操作。 重要的一点是, 抽象模板中还定义了一个称 作模板方法的法, 该法不仅包有抽象模板中表示算法步骤的方法调 用, 而且也可以包含有定义在抽象板中的其他对象方法用, 即模板 方法定义了法的
具体模 (Concrete Template):具体板是抽象模板的子,重写
2.3.2模板方法
模板方法模式 UML 类图 2-5
【结构描述
下面通过一个简单问题来述模板
类客运车站在安排乘客上车时都进行:全检查、验证车票,选车体类型三个步骤。 要求在一个抽象类 Station 包含有 safetyExamine()、 validateTicket()和 choiceCarriageType()三个表示乘车步骤的抽方法,而且该抽象类特别的包含有 ridingStep()方法,该方法顺序 地用 safetyExamine()\validateTicket()和 choiceCarriageType 方法,也就说抽象类 Station 使用 ridingStep()方法装了乘车步骤。 Station 的子类可以直接承 ridingStep ()方法,但必 须重写 safetyExamine()、 validateTicket()和 choiceCarriageType()方法,即子类须给出骤 的细节,比如 Station 的子类 RailwayStation 在实现 safetyExamine()、 validateTicket()和 choiceCarriageType()方法时,给出了自己的安全检查方式、检票方和所车
针对上述问题,使中介
(1)抽象模板:
本问题中,抽模板角色是 Station 类。抽模板的模板法是 ridingStep();抽象模板 中表具体骤的方是 safetyExamine(),balidateTicket()和 choiceCarriageType, 三者都是抽 象方
public abstract class Station {
public abstract String getName();
public abstract void safetyExamine();
public abstract void validateTicket();
public abstract void choiceCarriageType();
public final void ridingStep() { //模板方法
safetyExamine();
validateTicket();
choiceCarriageType();
}
}
(2)具体模板:
本问题中,具体模板是 RailwayStation
public class RailwayStation extends Station {
public void safetyExamine() {
System.out.println(
}
public void validateTicket() {
System.out.println(
}
public void choiceCarriageType() {
System.out.println(
}
public String getName() {
return
}
}
public class AutoStation extends Station {
public void safetyExamine() {
System.out.println(
}
public void validateTicket() {
System.out.println(
}
public void choiceCarriageType() {
System.out.println(
}
public String getName() {
return
}
}
下面应程序中, Applitcation.java 使用模方模式中所涉及的类, 运
public static void main(String args[]) {
Station station=new RailwayStation();
System.out.println(station.getName());
station.ridingStep();
station=new AutoStation();
System.out.println(station.getName());
station.ridingStep();
}
}
运行效果图 2-6
【适合使用策
可以通在抽象模板定义模板方法给成熟的算法骤, 同时又不限制步骤的节,
【优点及优势】 :
设计者要给出一个算法的固定步骤,并将某些骤的具体实现留子来现。 需要对代码进行重, 将各个类公共行为提取
3、总结
每个原则、 模式描了一个在我们周围不断重复发生问题以该问题解决案核心, 设 计则、 模式描了软件设计过程中某类常见题一般性解决方案, 向对象设计的几种基 本原、 模式描了面向对象计过程中、 特定景下、 类和相互通信对象间的常见组织关 系。面向对象计模式是解决 “ 类和相互通对象间的组织关系 ” 包括它们角色、职责、 协 方几个方,是 “ 好面向对象设计 ” ,所谓 “ 好面向对象计 ” 是那些可以满足 “ 应对变化 提高复用 ”
面向对象设计的种基本原则、 模式描述是软件设计, 此它是立于编语言但是 向对象设计模式最实现仍然要使用面对象编程语言来表达;向对象几种基本则、 设计模式像算法窍门技巧可以照搬照用, 它是建立在 “ 面向对象 ” 纯熟、 深入理解基础上 经验性认识, 怎样理地设计式的基本原则、 设计模式需要经一定时间的真思考、 学 习和编程实践才能悟出其中的
软件开发、 设计原则与设计模式的关系, 我不当比喻为争、 战略与术的关系; 要取得战争的全胜利, 你先要在战略上把握好,然后才是战术上指挥好;同样,要开发 出的软件, 首先要遵循一定的计原, 为了达到我们的目
参考文献
【 1】 、耿祥义、清华大学
【 2】 、 http://www.kuqin.com/design-patterns/20080727/12537.html 【 3】 、 (http://www.kuqin.com/design-patterns/20080727/12537.html)
转载请注明出处范文大全网 » 面向对象程序设计原则