从面相对象来思考设计模式
工作也好几年了,一直没有整理过面相对象的真谛。忙里偷闲借鉴一下前人的一些经验总结一下自己的感悟。
面相对象的3要素:封装、继承、多态
五个基本原则:单一职责原则(SRP)只做一件明确的事情
开发封闭原则(OSP)对扩展开放,对修改封闭
Liskov替换原则(LSP)子类可替换基类
依赖倒置原则(DIP)弱化依赖关系,接口和实现尽量分离
接口隔离原则(ISP)避免大接口,使用小接口
设计模式从根本上来说就是如何根据业务的需求设计一个健壮性、扩展性、高效率、低风险的系统。要实现这些优点,
就需要我们发挥面相对象的优势,根本上还是通过接口和抽象类对系统模块进行封装、继承和多态的操作来实现。
前人一共总结了23种设计模式,基本上覆盖了程序设计过程中的绝大部分可能出现的情况,但是我们也不应该拘泥于
书本上的结论,而是应该根据实际业务和实际需求来设计出我们自己最合适的程序架构。
一个对象的生命周期
- 对象创建:
想到对象创建,最多的就是通过new一个类型来创建对象。但也会有许多特殊的情况,例如对象创建过程很复杂,如何解耦?等等。
- 对象组合、包装:
一个对象创建后,可能需要对其就行包装或者封装,还可能由多个对象组成一个组合结构。在这过程中,也会遇到各种问题。
- 对象操作:
对象创建了,也组合、包装完毕,然后就需要执行对象的各种操作,这是对象真正起作用的阶段。对象的操作情况众多,问题也很多。
- 对象消亡:
直到最后对象消亡。
原型模式:主要适用于对象的拷贝,当需要用到一个复杂对象时,如果其中的一些属性和方法可以沿用的话,
我们可以调用IColoneable的Clone方法进行复制,这样这些属性和值就不用重新创建和赋值了。这里需要注意一点
就是深拷贝和浅拷贝。
深拷贝的对象会指向新的地址,新对象的值改变不会影响原对象的值;浅拷贝的话新对象和被拷贝的对象指向的值是
同一个存储地址,这样改变新对象或者旧对象的值的时候,两个对象都会改变。
单例模式:当我们对某个对象要求只能实例化一次的时候,就可以借鉴单例模式。缺点是无法作为对象赋值和传
递 。所以当我们使用的时候得考虑一下,当前对象的作用和功能使用单例模式是否恰当。具体使用就是将构造函数私有化,
通过一个静态函数来返回对象。
建造者模式:当我们初始化某个复杂对象需要根据不同情况给不同属性赋值的时候,通常我们是在构造函数里对属性
进行初始化然后返回对象。但是如果多人合作,比较复杂的功能时,这样非常不方便,这时候我们可以借助建造者模式的
思路。将对象的创建和初始化分离,通过创建不同的子对象来达到我们的目的。
简单工场模式:工厂就是封装一个对象的创建过程,对于一种抽象,具体由哪个具体实现,由工厂实现。
工厂模式简单理解就是:需要什么对象,工厂为我们产生什么对象。例如:我们一个系统需要同时访问SQL和Oracle数据库,
如果使用简单方式,需要访问SQl的时候初始化SQL访问对象,需要Oracle初始化Oracle,这样会产生很多的数据冗余问题。
现在用一个接口IDBHelp同时继承SQL和Oracle基类,这样不管我们使用Oracle还是SQL,根据需要访问的数据库类型,
初始化IDBHelp对象即可满足我们的需求。
public IDBHelp()
{
Switch(datatype)
{
case "SQL":
return new SQLDBBase();
case "Oracle":
return new OracleDBBase();
}
}工厂方法模型和抽象工场都是基于此基础再去分离和抽象而来的。
适配器模式:当我们基于已有框架和系统上做开发时,发现已有接口并不能满足我们的业务需求时,我们需要对接口
重新封装一下。通过一个类的接口转换成客户希望的另外一个接口,使原本由于接口不兼容而不能一起工作的那些类可以一起工作。
重新封装一下。通过一个类的接口转换成客户希望的另外一个接口,使原本由于接口不兼容而不能一起工作的那些类可以一起工作。装饰模式:当系统升级和维护的时候,需要给对象新增功能,如何保证“开放封闭原则”和“单一职责原则”呢?
这时候我们可以通过“抽象”和“隔离”的手段来达到我们的目的。
a.隔离原有功能和新功能
b.二者依赖同一抽象
c.外部调用觉察不出内部的变化
从上面的类图看,ConreteComponent是原始类型,Decorator是一个抽象类,它的派生类负责添加新功能。这里理解的重点,
在于Decorator类中有一个Component属性,相当于Decorator封装了一个Component,直接调用他原有的功能,并且可以新增功能。
当然,这些操作都是可以派生在子类中实现的。而且不同的子类可以实现增加不同的功能。