




已阅读5页,还剩10页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1. 单一职责原则(SRP)单一职责原则(SRP),就一个类而言,应该仅有一个引起它变化的原因。也就是说,不要把变化原因各不相同的职责放在一起,因为不同的变化会影响到不相干的职责。再通俗一点地说就是,不该你管的事情你不要管,管好自己的事情就可以了,多管闲事害了自己也害了别人。在软件设计中,如果一个类承担的职责过多,就等于吧这些职责耦合在一起,而一个职责的变化可能会削弱和抑制这个类完成其他职责的能力。这耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。软件设计真正要做的许多内容,就是发现职责并把那些职责相互分离。如果多于一个的动机去改变一个类,那么这个类就具有多余一个的职责,就应该要考虑类的职责分离。2. 开放-封闭原则(The Open-Closed Principle 简称OCP)开放-封闭原则,或叫开-闭原则,是说软件实体(类、模块、函数等)应该是可以扩展的,但是不可修改。不修改的意思就是是“你可以随便增加新的类,但是不要修改原来的类”。从这个角度去理解就好多了,其实这里还是一个隔离变化的问题。这个原则的两个特征:一个是对于扩展是开放的;另一个是对于更改是封闭的。我们在设计开发任何系统时,都不可能指望系统一开始就需求确定,就不再变化(要这样就太幸福了,哈哈),这是不现实的也是不科学的想法。既然需求是有一定变化的,那么如何在面对需求变化时,设计的程序可以相对容易的修改,不至于说,新需求一来,就要把整个程序推倒重来(这样会让程序员疯了不可,哈哈,你不想疯吧)。怎样的设计才能面对需求的改变却可以保持相对稳定,从而使得系统可以在第一个版本以后不断推出的新版本呢?开放-封闭原则就是我们的答案。在程序设计时,我们要时刻考虑尽量把类设计的足够好,写好了就不要去修改,如果有新的需求来了,我们增加一些类来完成新的需求,原来的代码能不动就不动。绝对的对修改关闭是不可能的,无论模块是多么的封闭,都会存在一些无法对之封闭的变化,既然不能完全封闭,设计人员必须对他设计的模块应该对那种变化封闭做出抉择、他必须事先猜测出最有可能发生变化的变化种类,然后构建抽象来隔离那些变化。开放-封闭原则是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所生成的巨大好处,也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅对程序中呈现出频繁变化的部分都做出抽象,然后,对于应用程序中的每部分都刻意定进行抽象同样不是一个好主意,拒绝不成熟的抽象和抽象本身一样重要。3. 依赖倒转原则(DIP Dependency Inversion Principle)依赖倒转原则:抽象不应该依赖于细节。细节应该依赖于抽象;高层不应该依赖于底层,两者都应该依赖于抽象。说白了就是要针对接口编程,不要针对实现编程。抽象的东西才是最稳定的,也就是说,我们依赖的是它的稳定。依赖倒转其实可以说是面向对象设计的标志,用哪种语言来编写程序不重要,如果编写是考虑的都是如何针对抽象编程而不是针对细节编程,即程序中的所有的依赖关系都是终止与抽象类或者接口,那就是面向对象的设计,反之就是过程化设计了。4. 里氏代换原则里氏代换原则(LSP):子类型必须能够替换掉他的父类型。说白了就是一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而他察觉不出父类对象和子类对象的区别,也就是说,在软件里面,把父类都替换成他的子类,程序行为没有变化。有了里氏替换原则,才是继承服用成为可能,只有当子类可以替换掉父类时,软件的功能不受到影响,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。有了里氏代换原则,才能使开放-封闭原则成为可能,正是由于子类型的可替换性才使得父类型的模块在无需修改的情况下扩展。5. 接口隔离原则(ISP)接口隔离原则(ISP):不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。这个说得很明白了,再通俗点说,不要强迫客户使用它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。6. 迪米特法则(LoD)迪米特法则(Law of Demeter或简写LoD)又叫最少知识原则(Least Knowledge Principle或简写为LKP):如果两个类不彼此之间直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某个方法的话,可以通过第三者转发这个调用。 迪米特法则首先强调的前提是在类的结构设计上,每一个类都应当尽量降低成员的访问权限。 迪米特法则其根本思想强调的是类之间的松耦合。类之间的耦合越弱,越利于复用,一个处于弱耦合的类被修改,不会对有关系的类造成波及。7. 合成/聚合复用原则(Composite/Aggregate Reuse Principle或CARP)合成/聚合复用原则(Composite/Aggregate Reuse Principle或CARP):经常又叫做合成复用原则(Composite Reuse Principle或CRP),就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新对象通过向这些对象的委派达到复用已有功能的目的。我白了就是要尽量使用合成/聚合,尽量不要使用继承。本文来自CSDN博客,转载请标明出处:/gtuu0123/archive/2009/06/19/4283921.aspx黑箱复用法则“封装、继承、多态”是面向对象编程的三大特性。“美丽、智慧、大方”是(我认为的)女人应具有的三大优点。然而我可以经常夸奖一个女人“最美丽,最智慧,最大方”;但我从来不敢自吹自己写的程序“最封装,最继承,最多态”。因为“封装、继承、多态”之间属于相形相克。相形者,指三者中缺少任意一个,则余下二个都将不存在;相克者,则是三者中任意一个如果被发挥或表现到极限,则余者同样无法生存。正由于此,可以说,在抽象意义上,任何时候我们进行的程序设计1,都是力图在针对当前的问题,调整出这三个特性的各自的最佳“实现度”。这也是所有程序员在不断培养,苦苦追求的设计能力。什么叫高手、老手?什么叫新手、生手?虽然我懂得“盐是咸的,味精是甜的,姜是辛”,但我始终做不出一手好汤。虽然我也明白“油门、刹车、方向盘”的作用,但当舒马赫在F1赛道上艺术地操作这三者时,我还在某个坡路上流汗:“又要刹车又要加油门为难人啊!”是的,编程的难点与技艺正在于此。好的程序设计得让人几乎要归之为“艺术”;而糟糕的设计,就像一个蹩脚的厨子走了,留下一桌恶心的菜,你却不得不去咀嚼它,消化它,其间之苦,真非言语所能表达的。很不幸,我就是这样一个蹩脚的厨子,说起来“饭菜”也做了10年矣,但依然无法用“封装、继承、多态”做“面向对象”这一道菜。我这学习编程的10载,倒几近完整地见证了中国软件开发行业发展的全过程。我也看到了很多程序员都和我一样,在不断的摸索、碰壁中缓慢地成长。好在,编程界的泰斗终于感到于心不忍了,开始提供编程界的“菜谱”。这就是如今火热之至的“设计模式”2。当然,正如万有引力一直存在着,而不是等到牛顿被苹果砸了以后才出现。“设计模式”其实一直存在于优秀程序员的设计里。不过是没有形诸于文字,而是表现在代码中。当然,也远远没有泰斗们所归结出来的模式那样具备抽象性、概括性和通用性。说到设计模式,我只是想进一步证明,一个程序员面对不同问题,其驾驭面向对象三大特性的能力的重要性。这篇小文不准备讲那23个经典模式。我想以最基本的“白箱、黑箱复用”为例,开始我的论题。首先,不要看到“黑白箱”就想到测试。“继承、聚合”分别二者的原意,在不同的编程语言里可能有不同的术语,这里我们用最直观的“白箱”,“黑箱”来表述。所引用的代码,来自于早些日子我在“非程序员”(一个国内专讲UML的网站)的BBS的发言。那时有一位可能比我还菜的家伙在上面质疑复用为何要分“白箱”“黑箱”,我一时技痒,上去口水了一番。下面我会通过一个有关“项目”的故事,将我当时用来论证的代码,串成一次代码设计的演进。先得说说“继承”。C+ 提供了三种三继承“private, protected, public”。考虑到JAVA和C# 均只能支持最通用的 public 继承,我们这里就仅以此为继承的标准。所谓的public 继承,字面意思是“公开继承”。要个比方就是除了“老子”声明要带到阴间的财产,其它的,它继承者,都可以获得,使用。(这是一个蹩脚的比喻,但我想你会承认它确实表达了公开继承和其它继承的不同L )。“公开继承”就是一种最常见的白箱复用的设计。它表示:“B复用A的功能,并且B可以了解A的内部细节”。接下来我们讲“黑箱复用”。可以推测,它表示:“B复用A的功能,但B无法看到A的内部细节”。这在像C#或JAVA这样不支持私有或保护继承,也不支持多重继承的语言,是一种极其常见的设计。“黑箱复用”的实现方法是:如果B类想复用A类的功能,不是从A类派生,而是将A类的对象,声明成为B类的成员数据。嗯,是该来举一个“实际项目”了。通过演示这个“项目”的实作,我想,就算你是外行人,你也应能了解一点:事实上程序员最后用指头敲写代码,其实那不算是编程,真的编程,在于之前他的大脑必须做的分析与设计(这句话一会儿我会继续重复)。(声明一下,以下故事纯属虚构)10年的编程生涯,嗯,我的家里有5台电脑了。书房和卧室各有一间,但因为搬家所以常常换,老婆也有一个(不允许再多,也不允许换)。前三年又有了一个女儿,由于出生“脑香门第”,所以最近小家伙也开始用上我的电脑。这些算是项目的背景和资源。项目的初始需求是这样:结婚后每天晚上我都在书房时和电脑打交道到很晚。于是我老婆认为应该把那台笔记本搬到卧室,并责令我写个程序,可以实现她在卧室通过电脑向我发号施令。这样就有了本项目的产生。作为“客户”,老婆当然希望她可以发各种各样的命令;而作为该项目的产品经理、技术架构师,开发负责人,代码撰写者及测试师于一身的我,当然明白正确地引导客户的需求是一个项目是否成功的最重要前提之一,同时也是对客户负责的表现。我向她解释了一个无所不包的软件,首先将让用户界面变得繁杂无比,用户极易操作失误,而失去耐心;其次是众多功能之间将互相牵制,导致表面上得到一个无所不包的软件,实际功能却强项不强,弱项更弱等等最后我也委婉地提到了它对开发周期的可能的影响,以及在开发和后期维护费用上恐怕会出现几何级的增长最后约定是只实现最为常见两条命令的发送:a)“老公限N分种内来睡觉,否则门将反锁。”;b)“脚已洗好,请来端盆。”有了具体的需求描述,这下显得清楚多了。当然,老婆也不吃素的。在具体功能之外,也提出一些速度,性能的要求(这样就可以杜绝我在限定时间内无反应,会推托是软件传送命令太慢等后路),最重要一点也提到该系统应具备一定的扩展性,以备今后增加新的命令的要求等等需求之后是概要设计,首先我确定通过局域网,采用SOCKET来实现传输,而不是通过串口并口红外线或蓝牙。无论是硬件还是软件,这方面的资源均充备,这算是对开发资源做了认真详实的调研并确定。然后我把数据流图画到了概要设计。在概要设计内,我也决定了将有采用.Net + C# 来进行开发,当然,也提到了采用Win32+ C或C+或JAVA 的可能性。最后我也在概要设计里提出,由于该系统的简小,在速度,性能,及扩展性并无太多要求,所以应将设计的天平侧向于“易用性”(以博取老婆欢心)。界面上的东西,及第二条命令数据的流程,均略。之后开始详细设计,秉承概要设计的思想,我觉得将两条命令的发送分别提供。那么要不要采用“多态”?即是否将发送两条命令的发送动作取同一命名?考虑到以后可能会有新的命令扩展,这里采用多态会带来麻烦。所以我在这一步详细设计里,放弃多态特性之一。很显然,我对“扩展性”虽然没有完全忽略,甚至是在概要和详细设计里都可见“扩展性”的影响,但问题我缺少对“扩展”与“易用”做深入的,更具体的考虑。所以下一步的错误的根本,已经埋下来。下面我开始提供设计的伪代码。假设C# 提供基类Socket,用于在网络发送数据。我没有标出函数参数 data 的数据类型。但显然,作为该类的设计者,他并不知道你要发送什么样的数据(老婆的命令?老板的命令?)所以这个Send () 可以发送的 data 肯定是无具体含义的。我们可称为无格式的数据。而我们要发送的两个有着具体意义的命令。根据前面设计。我们需要为这两个类分别提供发送函数。当然,这两个发送具体命令的函数,最终肯定是要调用上述系统提供的Send()命令来完成实际发送操作。让我们来继承它:是的,我派生了一个新类:“卧室的Socket”。这一命名表征了我心里其实很清楚,我要设计一个仅供卧室那端的人使用的Socket。而我对两个具体的命令,提供了名字直观的两个函数,这也充分体现了我正在按概要设计的要求进行详细设计:请看,通过我对原来的Socket 类的派生,以及我对它的Send()动作的扩展,就在原来抽象的,无特别应用方向的类的基础上,得到一个新类,它有具体应用方向,也有具体意义的动作。这比起拿起Socket就直接使用的人(这类人往往是C的高手);或者比起为了“多态”而“多态”,从而把新加的两个函数也命名为Send()的人(这往往是刚接触C+才几天的人),我的这个设计,确实显得很正确。然而,事实上,这个设计在面向对象编程的世界里,仍然是一个拙劣的设计。在面向对象编程领域里有经验的程序员,我想已经看出其中的欠妥之处。假设这个项目付诸实施了。当老婆的人倒也没有提出什么扩展。光阴荏苒,结婚三年过去了,我们有了一个孩子;然后又是三年过去了,我们的孩子也开始会在电脑上施展她的天才。对这个软件提出了她看法:“爸爸,应该增加一个给我送牛奶的命令”。扩展需求终于出现了。然而,6年过去了,我对这个软件的记忆是零。没有看设计文档,我就开始看代码。然后我看到一个类:BedroomSocket。我开始使用它,然后我看到它有三个有关发送的方法:bool Send();bool SendSackCommand();bool SendFootBathCommand();作为一个使用者,我并不想去花时间了解BedroomSocket的具体细节,所以我并不知道其中那个Send() 其实是来自Socket这个基类(在实际大型项目开发中,比如大型ERP,专门写上层业务逻辑的程序员,甚至是没有权限可以看到他所使用的类的设计文档,更看不到源代码)。我错误地认为当初设计BedromSocket时,可能是为了易于对付一些新加的命令,所以提供了一个通用的Send()方法。就这样,纵然有100个项目经理,也无法在第一时间内阻止我义无反顾地通过BedroomSocket的实例来调用Send(),我会发现这个Send()实在太好用了,什么格式的数据都可以发送。也就这样,一个项目原来的设计倾向开始出现偏差。如果这种情况在多人之间出现多次,那么一个项目的设计风格与模式,就将被每个人的理解而肢解成五花八门。不仅仅是在人的方面:理解,改错,扩展等方面会增加难度,而且对于代码本身,也必然由于模块之间接合困难,而需要增加很多附加代码,最终是程序运行效率低下。你可以怪罪后来者(在这个例子里仍然是“我”),不去深入学习需求,概要,设计文档。但正如我前面所言,对一个大的项目,会按设计的层次分成多个子项目; 要每一个人都去学习每一个项目的详细设计文档,并且最好是从需求开始看起,这是不可能的。再考虑那些中间件的实现,通常都凝聚了一个软企的核心技术这种情况下,分配在实现业务逻辑的程序员,没有权限去学习中间件的具体设计思路。大家看到的,永远只是对方的接口。类似于我看到了Bedroom接口透露出来的三个方法,但我不知道这些方法的实现背景。针对这个例子中碰上的问题。我们可以将“白箱复用”(这里是继承),改为“黑箱复用”。在这次设计中,Socket 的对象成为类 BedroomCommand的一个成员。类BedroomCommand不再是通过“继承”来获得网络发送的能力。而是通过“拥有”一个Socket对象来获得该对象所有公开的能力。由于Socket 的对象sender 在BedroomCommand 里被声明为私有(private,,或者也可以是保护protected),所以,有关Socket网络发送的能力,仅有BedroomCommand 的设计者可以直接获取和使用。这就是“黑箱复用”的一种常见方法。BedroomCommand 的使用者不再需要面对 Send() 。它所能看见和用到的接口,是BedroomCommand 提供三个意义明确的发送方法: public bool SendSackCommand (); public bool SendFootBathCommand (); public bool SendMilkCommand();这样,我们就解决前面的问题。我们实现了一个类,它提供了它应有的功能,同时杜绝提供它不该有的功能。这正是一个良好的设计的基本标准。这么看来,是不是黑箱复用总是白箱复用来得正确?答案当然不是如此,下面我们继续给这个设计制造问题想要给“设计”制造问题,最好的办法就是修改“需求”了。我们假设原来的 Socket 类在除了提供一个公开对外的Send()方法以外,还提供了一个保护的SetOptions()方法。该方法用于对网络发送做一些参数调整,以便可以定制出更符合具体要求的网络发送能力。class Socketpublic Send (data); /发送数据 protected SetOptions(); /定制网络条件 ;Socket 的设计者,认为SetOptions这一能力是不能直接对外公开,所以SetOptions被设计为“保护(protected)”。这就使得:除非是Socket本身或它的继承它的类,否则就无法使用到SetOptions。我们前面讲的“白箱复用”,正是继承。这就给我们出现一个两难:如果使用“白箱复用”,那么我们可以获得我们想要的SetOptions,但同时我们却不得不公开了我们不想公开的Send。如果使用“黑箱复用”,那么们可以不公开Send。但却无法获得SetOptions的能力。由此产生了“复合复用”。(一般来说,SetOptions() 在 Socket 里不会被设置成 virtual,所以在C# 里,我们加上 new 指示符,而在C+,最直接的方法是另取一个名字,比如叫 SetMyOptions(),如此可以避免关于编译器说我们覆盖了基类同名函数的小问题。如果SetOptions是virtual类,则不存在该问题。另外,在C+里, base.SetOptions(),应写成: Socket:SetOptions())问题得以完美解决。Socket提供的超强能力,只有BedroomCommand的设计者能获得,使用。并且通过BedroomCommand的设计者来决定要对外公开哪些能力。任何一个后来的程序员,无论他是老手还是新手,都不会在使用BedroomCommand上出现偏差。就算是我在下一个6年之后,我也能正确地使用BedroomCommand。这样的一个设计,针对当前问题,做到既有“粒度”又有“弹性”。由此引申出几个话题。第一,关于需求分析、概要设计、详细设计的划分。概要设计更多地是在将需求模块转换为设计模块。它从总体上把握了技术设计的可行性。着重表达各个设计模块之间的静态及动态关系,并由此确定各设计模块之间接口规划。一般地说,概要设计并不需求每个写代码的人都参加直接参加设计。它要求项目技术负责人了解技术实现上可行性,总体难度;它也要求技术负责人具备把握整个设计的风格、倾向、取舍;但它并不要求技术负责懂得每一个模块的具体实现。本例中,如果想在概要设计中就明确好BedroomCommand是如何实现,这是不现实的。一个概要设计的负责人如果此时就开始关心每个类是如何实现(继承?聚合?),那将使他陷入细节实现的泥潭。从而根本无法在整体把握设计。在概要设计的形成过程中,项目技术负责人必须基本得出项目开发的分工安排。最后由每个程序员以“概要设计”为纲领,分头研究+相互研讨,逐步得出各自负责模块的详细设计。详细设计也负有对概要设计反证的功能,当发现无法得出概要设计的实现时,应提交讨论,修改概要设计。当然,不同的项目情况,对需求,概要,详细工作划分,也会有所不同。有些行业用户,比如税务,银行,由于IT实施较早,本身具备有相当的软件开发能力。他们往往可以直接严格的,详细的需求,到软企的手里,不仅仅需求文档有了,连概要设计也出了一半。而更多的用户,比如企业用户,在需求上往往只有一句话:“我要一套超强的ERP,解决我所有问题_”。显然只能先行挖掘用户的“需求”了。第二,关于程序员的设计分工设计模块不是以“需求功能模块”来划分。大家的分工,一般也不应直接按功能模块分配。因为这样将迫使每个程序员都成为“七项全能”。这个问题的另一面,就是我个人认为,公司在招聘技术人才上,几乎没有任何“定向测试”,也没能得出任何量化的结果。而设计分工要求我们了解每个程序员特长,从而合理地定位。我个人非常倾向于以“界面(UI)、业务逻辑,中间件(包括定制控件),底层模块”为纵线先进行层面上的设计任务安排。然后如有需要,再在各个层面进行横向划分。代码复用是绝大多数程序员所期望的,也是OO的目标之一。总结我多年的编码经验,为了使代码能够最大程度上复用,应该特别注意以下几个方面。1、 对接口编程 对接口编程是面向对象设计(OOD)的第一个基本原则。它的含义是:使用接口和同类型的组件通讯,即,对于所有完成相同功能的组件,应该抽象出一个接口,它们都实现该接口。具体到JAVA中,可以是接口(interface),或者是抽象类(abstract class),所有完成相同功能的组件都实现该接口,或者从该抽象类继承。我们的客户代码只应该和该接口通讯,这样,当我们需要用其它组件完成任务时,只需要替换该接口的实现,而我们代码的其它部分不需要改变!当现有的组件不能满足要求时,我们可以创建新的组件,实现该接口,或者,直接对现有的组件进行扩展,由子类去完成扩展的功能。2、 优先使用对象组合,而不是类继承 优先使用对象组合,而不是类继承是面向对象设计的第二个原则。并不是说继承不重要,而是因为每个学习OOP的人都知道OO的基本特性之一就是继承,以至于继承已经被滥用了,而对象组合技术往往被忽视了。下面分析继承和组合的优缺点:类继承允许你根据其他类的实现来定义一个类的实现。这种通过生成子类的复用通常被称为白箱复用(white-box reuse)。术语白箱是相对可视性而言:在继承方式中,父类的内部细节对子类可见。对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组合对象来获得。对象组合要求对象具有良好定义的接口。这种复用风格被称为黑箱复用(black-box reuse),因为被组合的对象的内部细节是不可见的。对象只以黑箱的形式出现。继承和组合各有优缺点。类继承是在编译时刻静态定义的,且可直接使用,类继承可以较方便地改变父类的实现。但是类继承也有一些不足之处。首先,因为继承在编译时刻就定义了,所以无法在运行时刻改变从父类继承的实现。更糟的是,父类通常至少定义了子类的部分行为,父类的任何改变都可能影响子类的行为。如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。对象组合是通过获得对其他对象的引用而在运行时刻动态定义的。由于组合要求对象具有良好定义的接口,而且,对象只能通过接口访问,所以我们并不破坏封装性;只要类型一致,运行时刻还可以用一个对象来替代另一个对象;更进一步,因为对象的实现是基于接口写的,所以实现上存在较少的依赖关系。优先使用对象组合有助于你保持每个类被封装,并且只集中完成单个任务。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物(这正是滥用继承的后果)。另一方面,基于对象组合的设计会有更多的对象(但只有较少的类),且系统的行为将依赖于对象间的关系而不是被定义在某个类中。注意:理想情况下,我们不用为获得复用而去创建新的组件,只需要使用对象组合技术,通过组装已有的组件就能获得需要的功能。但是事实很少如此,因为可用的组件集合并不丰富。使用继承的复用使得创建新的组件要比组装已有的组件来得容易。这样,继承和对象组合常一起使用。然而,正如前面所说,千万不要滥用继承而忽视了对象组合技术。相关的设计模式有:Bridge、Composite、Decorator、Observer、Strategy等。下面的例子演示了这个规则,它的前提是:我们对同一个数据结构,需要以任意的格式输出。第一个例子,我们使用基于继承的框架,可以看到,它很难维护和扩展。abstract class AbstractExampleDocument/ skip some code .public void output(Example structure)if( null != structure )this.format( structure );protected void format(Example structure);第二个例子,我们使用基于对象组合技术的框架,每个对象的任务都清楚的分离开来,我们可以替换、扩展格式类,而不用考虑其它的任何事情。 class DefaultExampleDocument / skip some code .public void output(Example structure) ExampleFormatter formatter = (ExampleFormatter) manager.lookup(Roles.FORMATTER);if( null != structure ) formatter.format(structure);这里,用到了类似于抽象工厂的组件创建模式,它将组件的创建过程交给manager来完成;ExampleFormatter是所有格式的抽象父类;3、 将可变的部分和不可变的部分分离 将可变的部分和不可变的部分分离是面向对象设计的第三个原则。如果使用继承的复用技术,我们可以在抽象基类中定义好不可变的部分,而由其子类去具体实现可变的部分,不可变的部分不需要重复定义,而且便于维护。如果使用对象组合的复用技术,我们可以定义好不可变的部分,而可变的部分可以由不同的组件实现,根据需要,在运行时动态配置。这样,我们就有更多的时间关注可变的部分。对于对象组合技术而言,每个组件只完成相对较小的功能,相互之间耦合比较松散,复用率较高,通过组合,就能获得新的功能。4、 减少方法的长度 通常,我们的方法应该只有尽量少的几行,太长的方法会难以理解,而且,如果方法太长,则应该重新设计。对此,可以总结为以下原则: 三十秒原则:如果另一个程序员无法在三十秒之内了解你的函数做了什么(What),如何做(How)以及为什么要这样做(Why),那就说明你的代码是难以维护的,必须得到提高; 一屏原则:如果一个函数的代码长度超过一个屏幕,那么或许这个函数太长了,应该拆分成更小的子函数; 一行代码尽量简短,并且保证一行代码只做一件事那种看似技巧性的冗长代码只会增加代码维护的难度。5、 消除case / if语句 要尽量避免在代码中出现判断语句,来测试一个对象是否某个特定类的实例。通常,如果你需要这么做,那么,重新设计可能会有所帮助。我在工作中遇到这样的一个问题:我们在使用JAVA做XML解析时,对每个标签映射了一个JAVA类,采用SAX(简单的XML接口API:Simple API for XML)模型。结果,代码中反复出现了大量的判断语句,来测试当前的标签类型。为此,我们重新设计了DTD(文档类型定义:Document Type Definition),为每个标签增加了一个固定的属性:classname,而且重新设计了每个标签映射的JA
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 机关公务用车培训
- 2024年一月《陈情表》文学地理信息系统
- 2024年12月份超导电缆低温冻伤后遗症赔付标准
- 2024年3月份电力系统黑启动资源调用协议
- 母婴洗护行业汇报
- 2025年04月芜湖繁昌区青年就业见习岗位49人(第一期)笔试历年典型考题(历年真题考点)解题思路附带答案详解
- 防近视讲座课件
- 2024年4月份电动汽车换电站电力配额协议细则
- 2024年第一季度量子纠缠通讯性格隐私泄露防护条款
- 2025年03月重庆巫山县农业农村委员会招募农技推广服务特聘农技员3人笔试历年典型考题(历年真题考点)解题思路附带答案详解
- 《道德与法治》六年级下《我们爱和平》课件
- 卫生法(教学讲解课件)
- 高三冲刺100天励志主题班会课件
- 全国工业产品生产许可证申请书
- 德能勤绩廉个人总结的
- 中层干部岗位竞聘报名表格评分表格评分标准
- 思想道德与法治课件:第六章 第一节 社会主义法律的特征和运行
- 有限空间作业及应急物资清单
- 《个人信息保护法》解读
- 新疆高速公路建设工程季节性施工方案
- 新版(七步法案例)PFMEA
评论
0/150
提交评论