目录 start
目录 end
|2018-06-14| 码云 | CSDN | OSChina
-DRY Don’t Repeat Yourself
是一个最简单的法则,也是最容易被理解的。但它也可能是最难被应用的(因为要做到这样,我们需要在泛型设计上做相当的努力,这并不是一件容易的事)。它意味着,当我们在两个或多个地方的时候发现一些相似的代码的时候,我们需要把他们的共性抽象出来形一个唯一的新方法,并且改变现有的地方的代码让他们以一些合适的参数调用这个新的方法。
KISS Keep It Simple, Stupid
KISS原则在设计上可能最被推崇的,在家装设计,界面设计 ,操作设计上,复杂的东西越来越被众人所BS了,而简单的东西越来越被人所认可,比如这些UI的设计和我们中国网页(尤其是新浪的网页)者是负面的例子。 “宜家”(IKEA)简约、效率的家居设计、生产思路;“微软”(Microsoft)“所见即所得”的理念;“谷歌”(Google)简约、直接的商业风格,无一例外的遵循了“kiss”原则, 也正是“kiss”原则,成就了这些看似神奇的商业经典。而苹果公司的iPhone/iPad将这个原则实践到了极至。把一个事情搞复杂是一件简单的事,但要把一个复杂的事变简单,这是一件复杂的事。
-Program to an interface, not an implementation
【Composition over inheritance】
【CQS Command-Query Separation】
【YAGNI You Ain’t Gonna Need It 】
【Law of Demeter – 迪米特法则】
(Principle of Least Knowledge)
,其来源于1987年荷兰大学的一个叫做Demeter的项目。Single Responsibility Principle (SRP)
一个类,只做一件事,并把这件事做好,且只有一个引起它变化的原因。
Open/Closed Principle (OCP)
对扩展是开放的,而对修改是封闭的。
Liskov substitution principle (LSP)
“Subtypes must be substitutable for their base types”。
即:子类应该可以替换任何基类能够出现的地方,并且经过替换以后,代码还能正常工作。另外,不应该在代码中出现if/else之类对子类类型进行判断的条件。 里氏替换原则LSP是使代码符合开闭原则的一个重要保证。正是由于子类型的可替换性才使得父类型的模块在无需修改的情况下就可以扩展。
“正方形不是长方形”
和“鸵鸟不是鸟”
。“娣,美人也,爱娣,非爱美人也….盗,人也;恶盗,非恶人也。”
——妹妹虽然是美人,但喜欢妹妹并不代表喜欢美人。Interface Segregation Principle (ISP)
Dependency Inversion Principle (DIP)
高层模块不应该依赖于低层模块的实现,而是依赖于高层抽象。 举个例子,墙面的开关不应该依赖于电灯的开关实现,而是应该依赖于一个抽象的开关的标准接口,这样,当我们扩展程序的时候,我们的开关同样可以控制其它不同的灯,甚至不同的电器。 也就是说,电灯和其它电器继承并实现我们的标准开关接口,而我们的开关产商就可不需要关于其要控制什么样的设备,只需要关心那个标准的开关标准。这就是依赖倒置原则。 这就好像浏览器并不依赖于后面的web服务器,其只依赖于HTTP协议。这个原则实在是太重要了,社会的分工化,标准化都是这个设计原则的体现。
下面有几点指导意见,帮助你避免在面向对象设计中违反依赖倒置原则:
变量不能持有具体类的引用,就像订单方法代码中,你看不到new一样。
不要让派生自具体类,要派生就派生抽象类abstract
不要覆盖基类中已实现的方法,除非你要覆盖的是比较特殊的一部分代码。
Common Closure Principle(CCP)
一个包中所有的类应该对同一种类型的变化关闭。一个变化影响一个包,便影响了包中所有的类。一个更简短的说法是:一起修改的类,应该组合在一起(同一个包里)。如果必须修改应用程序里的代码,我们希望所有的修改都发生在一个包里(修改关闭),而不是遍布在很多包里。CCP原则就是把因为某个同样的原因而需要修改的所有类组合进一个包里。如果2个类从物理上或者从概念上联系得非常紧密,它们通常一起发生改变,那么它们应该属于同一个包。
CCP延伸了开闭原则(OCP)的“关闭”概念,当因为某个原因需要修改时,把需要修改的范围限制在一个最小范围内的包里。
Common Reuse Principle (CRP)
包的所有类被一起重用。如果你重用了其中的一个类,就重用全部。换个说法是,没有被一起重用的类不应该被组合在一起。CRP原则帮助我们决定哪些类应该被放到同一个包里。依赖一个包就是依赖这个包所包含的一切。当一个包发生了改变,并发布新的版本,使用这个包的所有用户都必须在新的包环境下验证他们的工作,即使被他们使用的部分没有发生任何改变。因为如果包中包含有未被使用的类,即使用户不关心该类是否改变,但用户还是不得不升级该包并对原来的功能加以重新测试。
CCP则让系统的维护者受益。CCP让包尽可能大(CCP原则加入功能相关的类),CRP则让包尽可能小(CRP原则剔除不使用的类)。它们的出发点不一样,但不相互冲突。
Hollywood Principle
好莱坞原则就是一句话——“don’t call us, we’ll call you.”。意思是,好莱坞的经纪人们不希望你去联系他们,而是他们会在需要的时候来联系你。也就是说,所有的组件都是被动的,所有的组件初始化和调用都由容器负责。组件处在一个容器当中,由容器负责管理。
简单的来讲,就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在:
不创建对象,而是描述创建对象的方式。
在代码中,对象与服务没有直接联系,而是容器负责将这些联系在一起。
控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。
好莱坞原则就是IoC(Inversion of Control)或DI(Dependency Injection)的基础原则。这个原则很像依赖倒置原则,依赖接口,而不是实例,但是这个原则要解决的是怎么把这个实例传入调用类中?你可能把其声明成成员,你可以通过构造函数,你可以通过函数参数。但是 IoC可以让你通过配置文件,一个由Service Container 读取的配置文件来产生实际配置的类。但是程序也有可能变得不易读了,程序的性能也有可能还会下降。
【 High Cohesion & Low/Loose coupling & – 高内聚, 低耦合 】
凝聚>松耦合>重用 参考博客: 为什么我停止使用Spring?
Convention over Configuration(CoC)
简单点说,就是将一些公认的配置方式和信息作为内部缺省的规则来使用。例如,Hibernate的映射文件,如果约定字段名和类属性一致的话,基本上就可以不要这个配置文件了。你的应用只需要指定不convention的信息即可,从而减少了大量convention而又不得不花时间和精力啰里啰嗦的东东。配置文件很多时候相当的影响开发效率。
Rails 中很少有配置文件(但不是没有,数据库连接就是一个配置文件),Rails 的fans号称期开发效率是 java 开发的 10 倍,估计就是这个原因。Maven也使用了CoC原则,当你执行mvn -compile命令的时候,不需要指源文件放在什么地方,而编译以后的class文件放置在什么地方也没有指定,这就是CoC原则。
Separation of Concerns (SoC)
是计算机科学中最重要的努力目标之一。这个原则,就是在软件开发中,通过各种手段,将问题的各个关注点分开。如果一个问题能分解为独立且较小的问题,就是相对较易解决的。 问题太过于复杂,要解决问题需要关注的点太多,而程序员的能力是有限的,不能同时关注于问题的各个方面。正如程序员的记忆力相对于计算机知识来说那么有限一样, 程序员解决问题的能力相对于要解决的问题的复杂性也是一样的非常有限。在我们分析问题的时候,如果我们把所有的东西混在一起讨论,那么就只会有一个结果——乱。
我记得在上一家公司有一个项目,讨论就讨论了1年多,项目本来不复杂,但是没有使用SoC,全部的东西混为一谈,再加上一堆程序员注入了各种不同的观点和想法,整个项目一下子就失控了。 最后,本来一个1年的项目做了3年。
实现关注点分离的方法主要有两种,一种是标准化,另一种是抽象与包装。标准化就是制定一套标准,让使用者都遵守它,将人们的行为统一起来,这样使用标准的人就不用担心别人会有很多种不同的实现,使自己的程序不能和别人的配合。 JavaEE就是一个标准的大集合。每个开发者只需要关注于标准本身和他所在做的事情就行了。就像是开发镙丝钉的人只专注于开发镙丝钉就行了,而不用关注镙帽是怎么生产的,反正镙帽和镙丝钉按标来就一定能合得上。不断地把程序的某些部分抽像差包装起来,也是实现关注点分离的好方法。 一旦一个函数被抽像出来并实现了,那么使用函数的人就不用关心这个函数是如何实现的,同样的,一旦一个类被抽像并实现了,类的使用者也不用再关注于这个类的内部是如何实现的。 诸如组件,分层,面向服务,等等这些概念都是在不同的层次上做抽像和包装,以使得使用者不用关心它的内部实现细节。 说白了还是“高内聚,低耦合”。
Design by Contract (DbC)
DbC的核心思想是对软件系统中的元素之间相互合作以及“责任”与“义务”的比喻。这种比喻从商业活动中“客户”与“供应商”达成“契约”而得来。例如:
供应商必须提供某种产品(责任),并且他有权期望客户已经付款(权利)。
客户必须付款(责任),并且有权得到产品(权利)。
契约双方必须履行那些对所有契约都有效的责任,如法律和规定等。
同样的,如果在程序设计中一个模块提供了某种功能,那么它要:
期望所有调用它的客户模块都保证一定的进入条件:这就是模块的先验条件(客户的义务和供应商的权利,这样它就不用去处理不满足先验条件的情况)。
保证退出时给出特定的属性:这就是模块的后验条件——(供应商的义务,显然也是客户的权利)。
在进入时假定,并在退出时保持一些特定的属性:不变式。
契约就是这些权利和义务的正式形式。我们可以用“三个问题”来总结DbC,并且作为设计者要经常问:
它期望的是什么?
它要保证的是什么?
它要保持的是什么?
根据Bertrand Meyer氏提出的DBC概念的描述,对于类的一个方法,都有一个前提条件以及一个后续条件,前提条件说明方法接受什么样的参数数据等,只有前提条件得到满足时,这个方法才能被调用;同时后续条件用来说明这个方法完成时的状态,如果一个方法的执行会导致这个方法的后续条件不成立,那么这个方法也不应该正常返回。
现在把前提条件以及后续条件应用到继承子类中,子类方法应该满足:
前提条件不强于基类.
后续条件不弱于基类.
换句话说,通过基类的接口调用一个对象时,用户只知道基类前提条件以及后续条件。因此继承类不得要求用户提供比基类方法要求的更强的前提条件,亦即,继承类方法必须接受任何基类方法能接受的任何条件(参数)。同样,继承类必须顺从基类的所有后续条件,亦即,继承类方法的行为和输出不得违反由基类建立起来的任何约束,不能让用户对继承类方法的输出感到困惑。
这样,我们就有了基于契约的LSP,基于契约的LSP是LSP的一种强化。
Acyclic Dependencies Principle (ADP)
包之间的依赖结构必须是一个直接的无环图形,也就是说,在依赖结构中不允许出现环(循环依赖)。如果包的依赖形成了环状结构,怎么样打破这种循环依赖呢?有2种方法可以打破这种循环依赖关系:第一种方法是创建新的包,如果A、B、C形成环路依赖,那么把这些共同类抽出来放在一个新的包D里。这样就把C依赖A变成了C依赖D以及A依赖D,从而打破了循环依赖关系。第二种方法是使用DIP(依赖倒置原则)和ISP(接口分隔原则)设计原则。
无环依赖原则(ADP)为我们解决包之间的关系耦合问题。在设计模块时,不能有循环依赖。
23种经典设计模式UML类图汇总
参考博客: 23种设计模式UML表示形式
参考博客: 23中设计模式类图和原理详解 参考博客: 23种设计模式类图总结
定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的用户。
参考博客: 设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 参考博客: Java消除ifelse
也就是说将一种需求的多种实现算法分别封装起来, 然后利用多态, 让调用方选择任一实现
单例模式(Singleton)
原型模式(Prototype)
建造者(Builder)
抽象工厂(Abstract Factory)
工厂方法(Factory Method)
Builder
Abstract Factory
Factory Method
Prototype
Singleton
适配器模式(Adapter)
桥接模式(Bridge)
组合模式(Compontent)
代理模式(Proxy)
享元模式(Flyweight)
外观模式(Facade)
装饰模式(Decorator)
1.为复杂的子系统提供一个简单的接口 2.客户程序与抽象类的实现部分有很大依赖性 3.构建一个层次结构的子系统时,适用外观模式定义子系统每层的入口
策略模式(Strategy)
命令模式(Command)
状态模式(State)
解释器模式(Interpreter)
模板方法(Template Method)
责任链模式(Chain of Responsibility)
迭代器模式(Iterator)
中介者模式(Mediator)
备忘录模式(Memento)
观察者模式(Observe)
访问者模式(Visitor)
Singleton 一个类只有一个实例易于外界访问 Spring将该模式运用的出神入化
Controller或者Service层中定义共享对象, 但是使用线程安全对象
static 有可能被实例化多个出来么
struts2 就是采用该模式
自己用Java重写一下这个例子, 并做出自己的总结