面向对象的特点:继承,多态,封装
面向对象的好处:通过封装,继承,多态把程序耦合性降低,使用设计模式,使得程序更加灵活,容易修改,并且容易复用
复制&复用
紧耦合&松耦合
对一个对象的抽象就是类,对一个类的抽象就是抽象类,抽象类里的接口就是对一个类方法的抽象
面向对象并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类
设计模式大体可分为三类:创建型模式,结构型模式,行为型模式
单一职责原则
:就一个类而言,应该仅有一个引起它变化的的原因,如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或抑制这个类完其他的职责的能力,这种耦合会导致脆弱的设计,当变化发生时,设计会遭到意想不到的破坏。软件设计真正要做的许多内容,就是发现职责并把那些职责分离开。
开放-封闭原则
:软件实体(类,模块,函数等)应该可以扩展,但是不可修改,
对于扩展是开放的,对于更改是封闭的的,面对需求的改变却可以保持稳定,
无论模块多么封闭,都会存在一些无法封闭的变化,既然不可能完全封闭,设计人员必须对于他设计的模块应该对哪种变化封闭做出选择,他必须猜测出最有可能发生变化的类,然后构造抽象来隔离那些变化,
在我们最初编写代码时,假设变化不会发生,当变化发生时,我们就创建抽象来隔离以后发生的同类变化。
面对需求吗,对程序的改动是通过增加新代码进行,而不是更改现有的代码
依赖倒转原则
:a.高层模块不应该依赖底层模块,两个都应该依赖抽象
b.抽象不应该依赖细节,细节应该依赖抽象。
说白了,就是要对接口编程,不要对实现编程,
依赖倒转其实可以说是面向对象设计的标志,用哪种语言来编写程序不重要,如果编写时考虑的都是如何针对抽象编程而不是针对细节编程,即程序中所有的依赖关系都是终止于抽象或者接口,那就是面向对象编程,反之既是过程化的设计了。
就像电脑的cpu,主板,硬盘等等都是面向接口的,坏了,换一块一就行,面向实现的话,就要对应每一个品牌,每一个型号,很是麻烦。
里氏代换原则
:子类必须能够能够替换掉他们的父类类型
只有子类可以替换掉父类,软件单位的功能不受到影响,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。
由于子类型的可替换性才使得使用父类类型的模块在无需修改的情况下就可以扩展
迪米特法则
:如果两个类不必彼此通讯,那么这两个类就不应当发生直接的相互作用,如果其中一个类需要调用另一个类的某一些方法的话,可以通过第三者转发这个调用。
在类的结构设计上,每一个类都应该尽量降低成员的访问权限,强调类之间的松耦合,耦合越弱,越利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。
合成/聚合复用原则
:尽量使用合成/聚合 ,尽量不要使用继承
创建型模式:
1.简单工厂模式
理解:核心,可复用,可维护,灵活性好,对业务进行封装
举例:算法器
每次增加业务需求,需要增加一个类,并且工厂类中需要增加一个case分支,不满足开闭原则,因为必须要改动工厂类。
简单工厂模式最大的优点就是工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖
2.策略模式
理解:它定义类算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的替换,不会影响到使用算法的客户。
策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成相同的工作,只是实现不同,他可以以相同的方式调用所有的算法,减少各种算法类与使用算法类的耦合。
策略模式的stratety类层次为context定义了一系列的可供重用的算法或行为,继承有助于析取出这些算法中的公共功能
策略模式的优点是简化了单元,因为每个算法都有自己的类,可以通过自己的接口单独测试。
当不同的行为堆砌在一个类中时,就很难避免使用条件语句来选择合适的语句,将这些行为封装在一个个独立的stategy类中,可以在使用这些行为的类中消除条件语句。
举例:商场促销
策略模式与简单工厂模式配合起来使用,有时可以使代码更加简洁
3.装饰模式
理解:动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式 比生成子类更为灵活。
举例:
装饰模式是利用setcompoment来对对象进行包装,这个样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加对象链中,
装饰模式是为已有功能动态的添加更多功能的一种方式
当系统需要新功能的时候,是向旧的类中添加新的代码,这些新加的代码通常装饰了原有类的核心职责或主要行为,从而增加主类的复杂度,而这些熊加入的东西仅仅是为了满足一些只在特定情况下才会执行的的特护霜行为的需要,装饰模式就提供了很好额解决方案。客户代码就可以在运行时根据需要,有选择的,顺序的使用装饰功能包装对象了。
4.代理模式
为其他对象提供一种代理以控制对这个对象的访问。
远程代理,也就是为了对象在不同的地址空间提供局部代表这样可以隐藏一个对象在不同地址空间的事实。
虚拟代理:根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真是对象。理解就是占位图
安全代理:用来控制真实对象的访问权限
只能指引:当调用真实的对象时,代理处理另外一些事
代理模式其实就是在访问对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。
5.工厂方法模式
理解:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到了子类。
工程方法的实现时,客户端需要决定实例化哪一个工厂来实现,选择判断的问题还是存在的,也就是把简工厂的逻辑移到了客户端代码来进行,你想加功能,本来是改工厂类的,而现在是改客户端。
6.原型模式
理解:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建类型的对象。
其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
一般在初始化的信息不发生改变的情况下,克隆是最好的办法,即隐藏了对象的实现细节,又是对性能的大大提高。
如果字段是值类型的,则对对象进行逐位复制,如果字段是引用类型,则复制引用但不复制引用对象,因此原始对象和其复本引用同一个对象。
浅复制:被复制的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象
深复制:把引用对象的变量指向复制过得新对象,而不是原来的被引用的对象。
7.模板模式
理解:定义一个操作中的算法骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法结构即可重定义该算法的某些特定步骤。
提炼代码
既然用了继承,并且肯定的这个继承的意义,就应该要成为子类的模板,所有重复的代码都应该上升到父类,而不是让每个子类都去重复。
当我们要要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理
模板方法模式通过把不变的行为搬到超类,去除子类中重复的代码来体现它的优势
8.外观模式
理解:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层的接口,这个接口使得这一子系统更加容易使用。
增加外观facede可以提供一个简单的接口,减少他们之间的依赖
在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,但因为他们又有非常重要的功能,新的需求开发必须依赖于它,此时用外观模式很合适,你可以为新系统开发一个外观类,来提供设计粗糙或高度复杂度的遗留代码的比较清晰的简单接口,然新系统与facede对象交互,facede与遗留代码交互所有复杂的工作。
9.建造者模式
如果我们使用建造者模式,那么用户就只需要指定需要建造的类型就可以了,而具体的建造过程和细节就不知道了
理解:将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示时可以使用次模式
建造者模式是在当创建的复杂对象的算法应该独立于该对象的组成部分以及他们的装配方法时使用
10.观察者模式
理解:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象状态发生改变时,会通知所有观察者对象,使他们能自动更新自己
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象的一致性,我们不希望为了维持一致性而使各类紧密耦合,这样会给维护,扩展,和重用带来不便。
时机:
当一个对象的改变需要同时改变其他对象时
当不知道具体多少对象有待改变时,
当一个抽象模型有两个面,其中一面依赖于另一面,使用观察者模式,将这两者都封装在独立的对象中使他们各自的变化都不会影响另一边的变化。
事件委托的实现:
类似于函数指针,block,lanumda
11.抽象工厂模式
理解:提供一个创建一系列相关或依赖对象的接口,而无需指定他们具体的类
工厂类与抽象工厂类结合
反射机制与抽象工厂结合
减少分支判断
12.状态模式
理解:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了类。
为了解决方法过长的坏味道,对代码进行责任分解
主要解决当控制一个对象状态的条件表达式过于复杂,把状态的判断转移到不同状态的一系列类中,可以把复杂 的判断逻辑简化。
状态模式好处是可以将与特定状态相关的行为局部化,并且将不同状态的行为分割开来,通过定义新的子类可以很容易的增加新的状态和转换
13.适配器模式
理解:将一个类的接口转换成客户希望的另一个接口,adapter模式使得原来由于接口不兼容而不能一起工作的那些类可以一起工作
使用一个已经存在的类,但如果他的接口,也就是他的方法和你的要求不相同时,可以考虑这种模式
两个类所做的事情相同或相似,但是接口不同
客户代码可以统一调用同一接口,这样可以更简单,更直接,更紧凑
在双方都不容易修改的时候再使用适配器模式,而不是一有不同就用,
例子:扁鹊的医术
14.备忘录模式
理解: 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象还原到原先的
状态。
要保存的细节风封装在memento中,适用于功能比较复杂,但需维护或记录属性历史的类
有命令撤销的类,可以使用
例子:游戏进度保存
把复杂对象内部信息对其他对象屏蔽起来
15.组合模式
理解:讲对象组合成树形结构以表示,部分-整体,的层次结构,。组合模式使得用户对单个对象和组合对象具有一致性
16.迭代器模式
理解:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
17.单例模式
理解:保证一个类仅有一个实例,并提供一个访问它的全局访问点
多线层的单例需要lock
双重lock
静态初始化可解决多线层问题,在自己被加载时就将自己实例化,又称为饿汉式单例
原先的是在使用时才初始化,称为懒汉式单例
18.桥接模式
理解:将抽象部分与他的实现部分分离,使他们都可以独立的变化
实际是指抽象类和他的派生类用来实现自己的对象
19.命令模式
理解:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,请求排队或记录日志,以及可撤销的操作
20.责任链模式
理解:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这个对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它.
接受者和发送者都没有对方的明确消息,且链中的对象自己也不知道链的结构,结果是职责链可简化为对象的相互连接,他们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用。
可以增加或修改一个请求的结构,增强了给对象指派职责的灵活性。
一个请求可能到了末端都得不到处理,或者因为没有正确的配置而得不到处理 ,需要事先考虑全面。
21.中介者模式
尽管将一个系统分割成许多对象可以增强其复用性,但是对象间的相互连接激增会降低其可复用性,因为大量的连接使得一个对象不可能在没有其他对象的支持下工作,系统表现为一个不可分割的整体,所以,对系统的行为进行任何较大的改动就十分困难。
理解:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显示的相互引用,从而使耦合松散,而且可以独立的改变他们之间的交互。
mediator
控制了集中化,中心化,把交互复杂性,变为了中介者的复杂性。
22.享元模式
理解:运用共享技术有效的支持大量细粒度的对象。
可以避免大量非常相似的类的开销,
内部状态:不会随环境改变而变化的共享部分,可称为享元的内部状态。
要改变的,不能作为共享的,就是享元的外部状态。
23.解释器模式
理解:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器需要解决的是,如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言的句子,这样就可以构建一个解释器。该解释器通过解释这些句子哦来解决问题,比如正则表达式
当有一个语言需要解释执行,并且你可以将该语言中的句子表示为一个抽象语法树时,可以使用解释器
用了解释器,意味着很容易改变和扩展文法,因为该模式使用类来表示文法规则,你可以使用继承来改变或扩展文法,
不足:文法中的每一条规则至少定义一个类,因此包含许多规则的文法可能难以维护和管理,建议文法非常复杂时,使用其他的技术如语法分析程序或编译生成器来处理。
24.访问者模式
理解:表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作
优点:增加新的操作很容易,增加一个新的访问者,将有关的行为集中在一个访问者对象中。
缺点:增加新的数据结构变得困难,尽量少用,除非必须得用