几个原则........
A.开-闭原则:
Software entities should be open for extension,but closed for modification.
B.合成复用原则:
就是说要少用继承,多用合成关系来实现。避免因修改基类造成"牵一发而动全身"的悲剧.
C.依赖倒转原则:
抽象不应该依赖与细节,细节应当依赖与抽象。
要针对接口编程,而不是针对实现编程。
传递参数,或者在组合聚合关系中,尽量引用层次高的类。
D.里氏替换原则:
用父类的地方,用子类也完全可以运行.
E.迪米特法则
最少知识原则。不要和陌生人说话。
一个模式的几个重要方面:
a.名称(用一两个词来描述模式的问题、解决方案和效果, 达到快速有效交流目的)
b.问题 (描述了应该在何时使用模式, 可给出不良设计)
c.方案 (描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式)
(服务端,客户端)
d.效果
一些总结:
工厂模式是对产品进行扩展,如果需要更多的扩展,比如对工厂本身进行扩展,那就是抽象工厂模式.
面向对象-设计模式
1. 将界面与业务逻辑分开.
A.计算器:
(1).将计算与界面(输入输出)分开.
(2).运用简单工厂模式,根据不同的运算符,定义不同运算类,利用一工厂类根据操作符的不同生成
不同类.
通过多态,利用 result = obj->operate(a ,b ); 计算出结果.
如果新增加运算符,只需要增加对应的运算类.
简单工厂模式示例:
class Operation{virtual void operate();};
class OperationAdd:Operation{ void operate();}
class OperationSub:Operation{ void operate();}
//简单式厂类:
class SimpleFactory{
Operation * getOperation(char ch){
switch( ch ){
case '+': return new OperationAdd;
case '-': return new OperationSub;
default: return 0;
}
}
};
//客户端代码: ........ 将选择留给简单工厂处理.
SimpleFactory sf;
Operation * op = sf.getOpertion('+');
op -> operate();
//即客户端要与两个类交互: 工厂类,抽像父类.
B.UML
+,-,# 表公有,私有,保护成员.
<- - - - : 表依赖关系,如作为参数,然后调用这个参数的方法.
<|- - - - :对接口的实现.
空心三角+实线: 继承. <|------------
关联:一个类要知道另一个类(作为成员). 箭头加实线
聚合:弱的拥有关系. 第一个人都属于人群. 空菱形(人群方)+实线箭头.
可在人群类中设一个数组.
组合:实心菱形(人)+实线箭头(手)
2.策略模式:(收银,打折问题)定义算法家族,让算法替换,不影响客户代码.
简单工厂模式:只是解决创建对象问题,根据不同的需要创建不同对象,对于每次扩展都要修改这个工厂.
Strategy:设抽像类,各种算法继承此Abstract类,使用时将算法作为一个new 对象传入 Context对象中,然后通过Context调用算法.
策略模式示例:
class Algorithm{ virtual void deal();};
class A1:Algorithm:Algorithm{ void deal(){ } };
class A2:Algorithm:Algorithm{ void deal(){ } };
class Context{
Context(Algorithm * pA){ this->pa=pA; }
void deal(){ pa-> deas();}
};
客户端: ...................// 由客户端来处理选择问题.
switch( Condition ){
case A1: ctxt = new Context( new A1() );
ctx -> pa -> deal();
return ;
}
//即客户端要与一个类交互: 上下文类...由传给Context的参数确定算法,并且通过Context来间接调用算法的方法.
//思考:策略模式封装了算法(变化),只要不同时间应用不同的业务规则,就可以考虑使用策
略模式了.
但是,由于还是在客户端通过 switch 来选择 context所用算法的,因此strategy并没有减轻客户端的选择压力.
3.单一职责原则:就一个类而言,应该仅有一个引起它变化的原因.
//游戏:将逻辑与界面分开.
4.开放封闭原则:软件实体可以扩展,但是不可修改.
5.针对接口编程.
6.只有当子类可替换掉父类时,父类才能真正被复用.
7.装饰模式:
利用setComponent来对对象进行包装(base=that)....在Operation中调用that的方法,然后加上自己的增加的功能.
8.代理模式:
代理者与间接执行者(Real)都继承同一个类,代理的动作其实都是通过间接执行者实现的.
代理中有Real的引用.
Proxy:Cx{
Proxy(){this->real=new Real;}
show(){ real->show(); }
}
9.工厂方法:解决简单工厂不符合开放封闭原则问题。。。。对每个操作类,都有相应的工厂类.
10.原型模式:利用一个原型,生成多个拷贝.......注意浅复制与深复制.
11.模板模式,尽可能把子类中相同的部分抽象到父类中.
12.外观模式,为系统中一组接口提供一致的高层接口.
13.建造者模式:动作实现者(提供一系列动作),指挥者(固定动作的执行顺序)
14.观察者模式:定义一种一对多的依赖关系,让多个观察者对象同时监听某主题对象,当这个主题对象在状态变化时,会通知所有观察者对象.
使用时机:当一个对象的改变需要同时改变其它对象的时候 ....而且它不知道有多少对象需要改变时。
示例:
15.抽象工厂: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类.
一个抽象工厂接口有多种实现,每种实现(具体工厂)都对应相应系列产品的创建方法.
//缺点:当有改变发生时,可能需要改变抽象工厂和具体工厂.(1抽+多具体)
//改进:用一个简单工厂来产生产品( 每类产品对应一个方法,并且在此方法中使用switch来决定产生产品的系列);
//当然,也可以利用反射技术,替代抽象工厂(免去switch结构<--修改了代码),
//反射+配置文件实现数据库访问(对不同数据库,编写不同工厂类)
16.状态模式:主要解决的是当控制一个对象状态转换条件表达式过于复杂时,把状态的判断逻辑转换到表示不同状态的一系列类中。
例:
//抽象状态类:
class State{
virtual Handle(Context ctxt){}
};
//具体状态:每个状态实现与Context的一个状态相关的行为...
class StateA : State{
Handle(Context ctxt){
ctxt.state = new StateB; //由状态A-》B
}
};
class StateB : State{
Handle(Context ctxt){
ctxt.state = new StateA; //由状态B-》A
}
};
class Context{
State state;
Request(){
state.handle(this); //由当前状态改变上下文状态.
}
};
//状态模式优点:将与状态相关行为局部化.
17.适配器模式:
系统的数数据和行为都对,但是接口不符 <---- 可用关联关系(作为成员)通过间接调用.
class Adapter{ //适配器
Data d;
void deal(){
d.doIt();
}
};
class Data{
void doIt(){}
};
18.备忘目模式:
角色(包含状态,及改变状态的行为) : 拥有恢复状态的方法
状态管理者(包含状态类) : 拥有设定状态的方法
状态类
19.组合模式:让用户一致地处理叶子结点与非叶子结点(包含一个List<Node*>即子结点.).
当你发现需求中体现部分与整体层次的结构时,以及你希望用户可忽略组合对象与单个对象的不同
,统一使用组合结构中所有对象时,就应该考虑使用组合模式了.
20.单例模式:保证一个类只有一个实例,并提供一个访问它的全局变量。
Object sysRoot = new Object;
Pointer * p = null;
getInstance(){return p ? p : p=new A ; } //注意在多线程中,要锁住另一辅助对象
Pointer * getInstance(){
lock(syscRoot){
if(instance == null)instnace == null;
}
return instance;
}
Pointer * getInstance(){ //改善,双重锁定.
if( null == instance){
lock(syscRoot){
if(instance == null)instnace == null;
}
}
return instance;
}
//当然,也可以直接使用静态初始化,解决线程问题.
21.桥接模式:
思考:N系列手机与M系列手机软件 的统一
A. 以系列分类继承 .... 当增加一个功能时...
手机品牌(父) M手机,N手机(子) M_功能A,M_功能B N_功能A,N_功能B
B. 以功能划分,在叶结点分系列.
手机软件(父) 功能A,功能B(子) A_N, A_M B_N, B_M
以上都是以继承为体系的,缺点:(A)增加一个品牌,(B)增加一个功能都影响很大!!!
桥接实现:
两个抽象基类: 手机品牌类, 软件类(实现为种软件). //两个种基类,品牌,软件
然后将手机品牌类的软件设置为对应软件类.
22.命令模式:
客户端,调用者(用List存储命令), 命令类
23.职责链模式:
对于有级别的处理,当一个类处理不了时,交给它的上级处理,直到处理完毕.
class HandleGradeN1{
HandleGread next; /*并且,该 next 可根据需要设定的 */
void Handle(Request req){
if(req.Num<100){ /* 处理 */}
else {
if(next) next.Handle(req);
}
}
}
24.中介者模式:
25.享元模式:
26.解释器模式:
27.访问者模式: