




已阅读5页,还剩11页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
GoF著作中未提到的设计模式(1):Archetype 半天也没能给这个设计模式想出一个中文名称,算了,有时候还是原版的更容易理解。 简单地说,Archetype设计模式的目的是将业务处理逻辑和具体实现分离,所以至少需要两个参与者:Decorator和Delegate,它们都实现同一个接口,Decorator负责处理业务逻辑,而Delegate负责具体的实现,在Decorator的通用业务逻辑处理过程中,会把具体实现委派给Delegate。(注:这里的Decorator并不是指”装饰者“设计模式) 咱们还是用个例子讲吧,假设系统中有一个记录各种事件的接口: public interface EventRecorder / 记录事件的内容 public void record(String event); 引入两个抽象类来达到处理逻辑和具体实现分离的目的: public abstract class EventRecorderDecorator implements EventRecorder protected EventRecorderDelegate delegate; public void setDelegate(EventRecorderDelegate delegate) this.delegate = delegate; public abstract class EventRecorderDelegate implements EventRecorder 下面是两个简单的逻辑处理(Decorator)类: / 简单的事件记录类 public class SimpleEventRecorder extends EventRecorderDecorator public void record(String event) / 附加当前的日期到事件的内容中 event = getDate() + event; / 当内容过长时省略显示 event = ellipseText(event); / 记录事件的内容 delegate.record(event); / 复杂的事件记录类 public class ComplicateEventRecorder extends EventRecorderDecorator public void record(String event) / 附加当前的日期到事件的内容中 event = getDate() + event; / 附加当前异常信息到事件的内容中 event = event+getExceptionText(); / 附加当前的内存、CPU占用率到事件的内容中 event = event+getMachineStatus(); / 当内容过长时省略显示 event = ellipseText(event); / 记录事件的内容 delegate.record(event); 可以看到,最后一步都交给了EventRecorderDelegate对象,这一步就是之前所说的“具体实现”,有以下几种记录事件内容的可能性:1、记录到数据库中2、记录到本地文件中3、通过邮件发送4、发送到远程服务器中 所以我们需要新建四个EventRecorderDelegate的派生类来实现这些记录方式: public class RecordEventToDatabase extends EventRecorderDelegate public void record(String event) / 将记录写入到数据库中 public class RecordEventToFile extends EventRecorderDelegate public void record(String event) / 将记录写入到文件中 public class RecordEventByEmail extends EventRecorderDelegate public void record(String event) / 将记录发送到指定的邮箱 public class RecordEventToRemoteServer extends EventRecorderDelegate public void record(String event) / 将记录发送到远程服务器上 下面是一个生成事件记录对象的工厂: public class EventRecorderFactory public static EventRecorder create(int type, int flag) EventRecorderDelegate delegate = null; EventRecorderDecorator decorator = null; if(type = 0) decorator = new SimpleEventRecorder(); if(type = 1) decorator = new ComplicateEventRecorder(); if(flag = 0) delegate = new RecordEventToDatabase(); if(flag = 1) delegate = new RecordEventToFile(); if(flag = 2) delegate = new RecordEventByEmail(); if(flag = 3) delegate = new RecordEventToRemoteServer(); / 设置代理 decorator.setDelegate(delegate); 从我们举的例子中可以看到,有2种业务处理逻辑,有4个具体实现,它们组成了8种事件记录方式,另外,4个具体实现单独使用的话又有4种记录方式,实际上有12种事件记录方式。 分类: 设计模式GoF著作中未提到的设计模式(2):Interceptor 拦截器模式为我们提供了一种拦截方法调用或消息的途径,整个过程是自动的、透明的,下面是一个简单的拦截器示意图: 从图中可以看到,拦截器可以访问到方法调用的输入参数和返回结果,这样的话,拦截器能做的事儿就多啦,比如: 1、验证输入参数是否正确 2、偷偷地修改参数的值,例如参数类型的自动转换等 3、依赖注入 4、修改返回结果的内容、格式等 下面是一个包含我们要拦截的方法的类:public class Action / 拦截器集合的迭代器 private Iterator interceptors; / 输入参数 private Parameter param; / 返回结果 private Result result; / 构造函数 public Action(Parameter param); / 这个方法是我们要拦截的(具体实现见下面) public Result invoke(); / 其他. 下面声明一个拦截器接口:public interface Interceptor public Result intercept(Action action); 我们可能会想到以下的拦截方式:/ 先在方法调用之前拦截一下,可以处理输入参数intercept(param);/ 调用方法result = action.invoke(param);/ 在方法调用之后再拦截一下,可以处理返回结果intercept(result);这种方式的缺点是不能完全地控制方法的调用,比如不能跳过方法的调用而直接返回结果、不能更改所在对象内部的状态等。下面的实现也能达到方法调用的前后拦截,并且有完全控制该对象的能力public Result invoke() if( interceptors.hasNext() ) Interceptor interceptor = interceptors.next(); result = ercept(this); 下面我们举几个拦截的具体例子:/ 参数合法性验证拦截器public ParamInvalidator implements Interceptor public Result intercept(Action action) Paramemter param = action.getParam(); / 确保参数不为null if(param = null) addMessege(param is null!); / 创建一个默认的参数对象 action.setParam(new Paramemter(); / 继续调用过程 return action.invoke(); 一般来说,这类拦截器应该放在拦截器集合的最前面,所以,拦截器的被执行顺序是比较重要的!这依赖于具体的实现需求。如果需求有要求:参数为null时直接返回一个null的结果,停止调用过程,那么我们可以把上面的方法改成这样:public Result intercept(Action action) Paramemter param = action.getParam(); if(param = null) return null; / 继续调用过程 return action.invoke();所以,在所有的拦截器的实现中,action.invoke()这一行代码的位置或者有无非常重要,通过控制它我们就能在调用的前后进行拦截,甚至不调用它!public interface MoneyAware public void setMoney(int money);/ 依赖注入拦截器public DependencyInjector implements Interceptor public Result intercept(Action action) / 如果它实现了MoneyAware接口,那么我们就给它注入5毛钱 if(action instanceof MoneyAware) action.setMoney(5); / 继续调用过程 return action.invoke(); 从这个拦截器可以看出,我们能修改被拦截对象的内部状态。 / 结果格式化拦截器public ResultFormater implements Interceptor public Result intercept(Action action) / 先调用要拦截的方法 result = action.invoke(); / 将结果格式化 formatResult(result); / 返回结果 return result; 这个拦截器就是方法调用后的拦截,所以这种拦截器被执行的时候被放在调用堆栈的最下面,当其他拦截器执行完后,它才被执行!GoF著作中未提到的设计模式(3):Null Object Null Object模式的目的包括: 1. 当对象提供者无法提供指定类型的对象时, 返回一个什么都不做的对象, 这对调用者是透明的,并且调用者不用判断获得的对象是否为null了,当然,对象提供者必须告知调用者(通过约定等).2. 有时候需要传递一个什么都不做的某个类型的对象给合作方. 例如某个函数需要实现特定接口的对象(通过参数传入)进行某些操作, 该函数的调用者在某些情况下希望不进行这些操作,那么他就可以传进来一个实现了该接口但函数体全为空的对象,这个对象就是Null Object. 举个例子,从某处(不是通过new来创建)获得一个对象后,我们的第一反应就是判断这个对象是否为null,这都成为程序员的本能了。如果为null,则做一些特殊处理,就像下面的代码片段: EventRecorder recorder = EventRecorderFactory.getRecorderByType(0); if( recorder = null ) Log.error(Recorder对象为空); lastErrorCode = 0; else recorder.record(记录点啥.); 看到了没有,为了处理这个对象为null的情况,增加了很多行代码,而且类似的代码片段充斥在整个项目中,看着都想吐了。 要是EventRecorder的作者拍着胸脯向你保证:我给你的EventRecorder对象绝对不会是null!不然我生孩子没.人家都这么说了,那咱就应该相信他!以后写代码就舒心多了,看着也清爽:EventRecorder recorder = EventRecorderFactory.getRecorderByType(0);recorder.record(终于不用判断是否为NULL了.);Null Object模式就可以实现上面的约定。下面是EventRecorder的声明: public interface EventRecorder public void record(String event);增加两个实现类: public class RecordEventToDatabase implements EventRecorder public void record(String event); / 记录内容到数据库中 public class RecordEventToFile implements EventRecorder public void record(String event); / 记录内容到文件中 下面是EventRecorderFactory中getRecorderByType的简单实现: public static EventRecorder getRecorderByType(int type) EventRecorder recorder = null; if(type = 0) recorder = new RecordEventToDatabase(); else if(type = 1) recorder = new RecordEventToFile(); return recorder;可以看出这个方法的返回值可能是null,调用者就需要判断这种情况。下面我们实现一个什么都不做的EventRecorder: public class NullEventRecorder implements EventRecorder public void record(String event); 下面是修改后的getRecorderByType: public static EventRecorder getRecorderByType(int type) EventRecorder recorder = null; if(type = 0) recorder = new RecordEventToDatabase(); else if(type = 1) recorder = new RecordEventToFile(); else recorder = new NullEventRecorder(); / 这就是Null Object return recorder;这样就可以保证该方法的返回值永远不会为null了。再举一个例子来说明第二个目的: / 付款人接口 public interface Payer public void pay(int money);/ 使用信用卡付款public PayerByCard implements Payer public void pay(int money) / 刷卡 / 不付款(这就是一个Null Object, 什么都不做)public NullPayer implements Payer public void pay(int money) 下面是一个使用Payer对象的方法:public void pay(Payer payer) if(payer=null) throw Exception; payer.pay();下面是一个使用场景:Payer payer = null;if(userType = 黑社会老大) payer = new NullPayer();else payer = new PayerByCard();payer.pay();/ 享受服务.GoF著作中未提到的设计模式(4):Double Dispatch 我们先从字面上去理解它吧,直观地说,它指的是两次dispatch。这里的dispatch指的是什么呢?举个例子: class Event public: virtual void PrintName() cout我是通用事件endl; class KeyEvent:public Event public: virtual void PrintName() cout我是按键事件endl; class ClickEvent:public Event public: virtual void PrintName() cout我是单击事件PrintName();什么时候会用到两次dispatch呢? 继续往下看: class EventRecorder public: virtual void RecordEvent(Event* event) cout使用EventRecorder记录通用事件 endl; virtual void RecordEvent(KeyEvent* event) cout使用EventRecorder记录按键事件 endl; virtual void RecordEvent(ClickEvent* event) cout使用EventRecorder记录单击事件 endl; class AdvanceEventRecorder:public EventRecorder public: virtual void RecordEvent(Event* event) cout使用高级EventRecorder记录通用事件 endl; virtual void RecordEvent(KeyEvent* event) cout使用高级EventRecorder记录按键事件 endl; virtual void RecordEvent(ClickEvent* event) cout使用高级EventRecorder记录单击事件RecordEvent(pEvent);输出内容为:使用高级EventRecorder记录通用事件实际上,在这个场景中,我们期望调用的是:AdvanceEventRecorder:RecordEvent(KeyEvent* event)下面我们使用Double Dispatch设计模式来达到上面的代码片段的目的,在所有Event对象中增加下面的函数: virtual void RecordEvent(EventRecorder* recorder) recorder-RecordEvent(this); 下面的代码片段将输出:使用高级EventRecorder记录按键事件 EventRecorder* pRecorder = new AdvanceEventRecorder(); Event* pEvent = new KeyEvent(); pEvent-RecordEvent(pRecorder);可以看出,第一次dispatch正确地找到了KeyEvent的RecordEvent(EventRecorder* recorder),第二次dispatch找到了AdvanceEventRecorder的RecordEvent(KeyEvent* event)。 Visitor模式就是对Double Dispatch的应用,另外,在碰撞检测算法中也会经常用到。Object Pool,即对象池,对象被预先创建并初始化后放入对象池中,对象提供者就能利用已有的对象来处理请求,减少对象频繁创建所占用的内存空间和初始化时间, 例如数据库连接对象基本上都是创建后就被放入连接池中,后续的查询请求使用的是连接池中的对象,从而加快了查询速度。类似被放入对象池中的对象还包括 Socket对象、线程对象和绘图对象(GDI对象)等。 在Object Pool设计模式中,主要有两个参与者:对象池的管理者和对象池的用户,用户从管理者那里获取对象,对象池对于用户来讲是透明的,但是用户必须遵守这些对 象的使用规则,使用完对象后必须归还或者关闭对象,例如数据库连接对象使用完后必须关闭,否则该对象就会被一直占用着。 对象管理者需要维护对象池,包括初始化对象池、扩充对象池的大小、重置归还对象的状态等。 对象池在被初始化时,可能只有几个对象,甚至没有对象,按需创建对象能节省资源和
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 航空航天复合材料 课件知识点3 聚合物基复合材料制备工艺
- 社会稳定测试题及答案
- 储备兽医面试题及答案
- 折花技能培训
- 四肢骨折护理常规
- 纵膈肿瘤切除术诊疗规范
- 2025年中国喷射式干手机行业市场全景分析及前景机遇研判报告
- 2025年中国尼龙钓鱼线行业市场全景分析及前景机遇研判报告
- 美容店入职培训
- 砖瓦行业安全培训
- 宣传片视频拍摄投标方案(技术方案)
- 德勤-问题解决策略与实践-客户服务培训手册课件
- 2025年山东产权交易集团有限公司招聘笔试参考题库含答案解析
- 《浙江市政预算定额(2018版)》(第七册-第九册)
- DB32-T 4878-2024 居住区供配电设施建设标准
- 2025年河北交通投资集团公司招聘笔试参考题库含答案解析
- 药品配送包装及运输方案
- 经济师考试知识产权高级经济实务新考纲题库详解(2025年)
- 新课标(水平三)体育与健康《篮球》大单元教学计划及配套教案(18课时)
- 医院培训课件:《失血性休克的急救护理》
- 2024年北京市中考生物真题卷及答案解析
评论
0/150
提交评论