面向对象程序设计设计模式论文邓鹏辉.docx
- 文档编号:25277607
- 上传时间:2023-06-06
- 格式:DOCX
- 页数:20
- 大小:87.18KB
面向对象程序设计设计模式论文邓鹏辉.docx
《面向对象程序设计设计模式论文邓鹏辉.docx》由会员分享,可在线阅读,更多相关《面向对象程序设计设计模式论文邓鹏辉.docx(20页珍藏版)》请在冰豆网上搜索。
面向对象程序设计设计模式论文邓鹏辉
面向对象程序设计
设计模式论文
姓名:
邓鹏辉班级:
软硕4班学号:
M201376109
一.程序设计目标和使用说明
该程序在eclipse3.2版本中完成,用的是jdk1.5。
该程序的设计目的是为了学习java设计模式,应用其中的少数几个模式编写一个程序,在编写程序的过程中亲身实践相应设计模式,学习体会。
该程序的设计目标是完成一个餐厅的经营流程。
其中的角色包括消费者,服务员,经理,以及厨房的厨师。
在程序设计中有四个包。
图1-1项目包
1.client包。
图1-2Client包文件
其中利用策略模式,对顾客进行划分。
让顾客具有各自不同的特点和属性,并且可以在程序运行的时候,利用相关方法进行修改,实现客户在进行时的需求更改。
2.waiter包。
图1-3waiter包文件
在waiter包中,是利用观察者模式实现的餐厅服务系统。
经理作为subject,然后服务员作为Observer,订阅信息。
在信息改变的时候,由经理通知所有的服务员,以便所有的服务员得到最新的信息,在业务方面不会出错。
然后由于餐厅厨房里也需要知道菜单信息,以及及时更改的信息。
所以将chef也作为订阅者加入到list中,跟服务员一起接收新的信息。
3.kitchen包。
包括文件:
图1-4kitchen包文件
利用模板模式将菜肴加工的过程进行优化,将相同步骤抽象出来。
然后又利用简单工厂模板方法来将菜类进行抽象,利用一个例子,将牛肉类进行抽象。
4.myrestaurant包。
其中包括main方法。
图1-5myrestaurant包文件
在该包中,main方法中导入前三个包,进行综合调用。
综合利用之前的各个角色,可以充分模拟餐厅的基本业务。
实例一个晚宴和午餐的客人。
他们是根据自己的特点来构造了自己的属性。
后来他们又更改了自己选择。
然后他们提交点单给经理,经理会同志所有服务员和厨师。
厨师会根据自己读到的点单来做菜。
二.模板及其描述
本程序中综合运用了策略模式,观察者模式,模板模式和工厂模式。
下面就四个模式分别进行说明。
1.
2.
2.1策略模式
策略模式(StrategyPattern)中体现了两个非常基本的面向对象设计的基本原则:
封装变化的概念;编程中使用接口,而不是对接口实现。
策略模式属于对象行为型设计模式,主要是定义一系列的算法,把这些算法一个个封装成拥有共同接口的单独的类,并且使它们之间可以互换。
策略模式使这些算法在客户端调用它们的时候能够互不影响地变化。
这里的算法不要狭义的理解为数据结构中算法,应该理解为不同的业务处理方法。
这种做法会带来什么样的好处呢?
它将算法的使用和算法本身分离,即将变化的具体算法封装了起来,降低了代码的耦合度,系统业务策略的更变仅需少量修改。
算法被提取出来,这样可以使算法得到重用,这种情况还可以考虑使用享元模式来共享算法对象,来减少系统开销(但要注意使用享元模式的建议条件)。
先看看策略模式的结构:
要使算法拥有共同的接口,就要实现一个接口或者一个抽象类出来才行。
这样结构的轮廓也就出来了,可用简单的类图来表示它们之间的关系:
图2-1策略模式类图
策略模式由三个角色组成:
算法使用环境角色:
算法被引用到这里和一些其它的与环境有关的操作一起来完成任务;
抽象策略角色:
规定了所有具体策略角色所需的接口。
在java它通常由接口或者抽象类来实现;
具体策略角色:
实现了抽象策略角色定义的接口。
图2-2Client包文件
在此包中,CookingOrder,SweetOrder,DrinkOrder为三个接口,分别用来定义顾客的三个餐饮属性。
FiveCooking,SevenCooking,TatalCooking为对接口CookingOrder的实现。
SweetOk,SweetNo为对SweetOrder的实现。
DrinkTea,DrinkCoffee,DrinkUsquebaugh为对接口DrinkOrder的实现。
分别完成对菜式的要求,甜点的要求,和酒水的要求。
接口只提供空方法,后面继承类个别实现。
举一例:
a)接口SweetOrder
packageclient;
publicinterfaceSweetOrder{
publicStringsweet();
}
提供一个抽象方法。
b)类SweetOk
packageclient;
publicclassSweetOkimplementsSweetOrder{
publicStringsweet(){
System.out.println("IwanttheSweet");
return"IwanttheSweet";
}
}
c)类SweetNo:
packageclient;
publicclassSweetNoimplementsSweetOrder{
publicStringsweet(){
System.out.println("IdonotwanttheSweet");
return"IdonotwanttheSweet";
}
}
而客人类client则面向接口编程,并使整个客人类中的属性可以利用接口和其方法实现自选和变更。
publicabstractclassClients{
CookingOrdercookingOrder;
SweetOrdersweetOrder;
DrinkOrderdrinkOrder;//面向接口编程
publicClients(){}
publicvoidsetCookingOrder(CookingOrdercook){
cookingOrder=cook;
}//动态设置点餐要求
面向接口编程,即利用接口将不同的接口实现包括进去,实现多项选择,策略变化。
而DinnerClient则是一个具体的客人类,根据晚宴的要求,针对自己实现有特点的选择。
2.2观察者模式
在设计一组依赖的对象与它们所依赖的对象之间一致(同步)的交流模型时,观察者模式(ObserverPattern)很有用。
它可以使依赖对象的状态与它们所依赖的对象的状态保持同步。
这组依赖的对象指的是观察者(Observer),它们所依赖的对象称为主题(Subject)。
为了实现观察者(Observer)的状态与主题(Subject)保持同步,观察者模式(ObserverPattern)定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。
这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
由于给定主体的观察者链表需要动态的变化,因此一个主题不能维护一个静态的观察者链表。
因此关注于主题状态的任何对象都需要明确地注册自己为主体的一个观察者。
主题状态发生的变化,都需要通知所有的以注册的观察者。
从主题接到通知以后,每一个观察者查询主题,使自己的状态与主题的同步。
因此一个主题扮演着发布者的角色,发布信息到所有的以订阅的观察者。
换句话说,主题和它的观察者之间包含了一对多的关系。
当主题的实例的状态发生变化时,所有的依赖于它的观察者都会得到通知并更新自己。
每一个观察者对象需要向主题注册,当主题的状态发生变化的时候得到通知。
一个观察者可以注册或者订阅多个主题。
当观察者不希望再得到通知时,它可以向主题进行注销。
本模式的类图结构如下:
图2-3观察者模式的静态结构
在观察者模式里有如下的角色:
抽象主题(Subject)角色:
主题角色把所有的观察者对象的引用保存在一个列表里;每个主题都可以有任何数量的观察者。
主题提供一个接口可以加上或撤销观察者对象;主题角色又叫做抽象被观察者(Observable)角色;
图2-4抽象主题角色
抽象主题角色,有时又叫做抽象被观察者角色,可以用一个抽象类或者一个接口实现;在具体的情况下也不排除使用具体类实现。
抽象观察者(Observer)角色:
为所有的具体观察者定义一个接口,在得到通知时更新自己;
图2-5抽象观察角色
抽象观察者角色,可以用一个抽象类或者一个接口实现;在具体的情况下也不排除使用具体类实现。
具体主题(ConcreteSubject)角色:
保存对具体观察者对象有用的内部状态;在这种内部状态改变时给其观察者发出一个通知;具体主题角色又叫作具体被观察者角色;
图2-6具体主题角色
具体主题角色,通常用一个具体子类实现。
具体观察者(ConcreteObserver)角色:
保存一个指向具体主题对象的引用;和一个与主题的状态相符的状态。
具体观察者角色实现抽象观察者角色所要求的更新自己的接口,以便使本身的状态与主题的状态自恰。
图2-7具体观察者角色
具体观察者角色,通常用一个具体子类实现。
观察者模式的效果:
观察者模式的效果有以下的优点:
第一、观察者模式在被观察者和观察者之间建立一个抽象的耦合。
被观察者角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口。
被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。
由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
如果被观察者和观察者都被扔到一起,那么这个对象必然跨越抽象化和具体化层次。
第二、观察者模式支持广播通讯。
被观察者会向所有的登记过的观察者发出通知。
观察者模式有下面的缺点:
第一、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
第二、如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。
在使用观察者模式是要特别注意这一点。
第三、如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
第四、虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。
在本设计中,经理需要接受点单,然后通知所有的服务员以及做菜的师傅。
由于点单要及时也要高效经济,所以特别适用观察者模式。
经理为Subject
publicinterfaceManagerSubject{
publicvoidregisterObserver(WaiterObservero);
publicvoidremoveObserver(WaiterObservero);
publicvoidnotifyObservers();
}//接口声明。
以下为经理的具体类。
importjava.util.*;
publicclassManagerimplementsManagerSubject{
privateArrayListwaiterObservers;//储存订阅者,及保存餐厅所有服务员,以及后面厨房的厨师
privateStringnewOrder;//保存定单
publicvoidManager(){
waiterObservers=newArrayList();
}
//通知所有的订阅者,及及时将新的定单或修改的定单通知给所有的服务员,以及后面厨房的厨师
publicvoidnotifyObservers(){
//TODOAuto-generatedmethodstub
for(inti=0;i WaiterObserverobserver=(WaiterObserver)waiterObservers.get(i); observer.update(newOrder); } } //注册订阅者,及给餐厅增加服务员,以及后面厨房的厨师 publicvoidregisterObserver(WaiterObservero){ //TODOAuto-generatedmethodstub waiterObservers.add(o); } //移除订阅者,开除服务员,以及后面厨房的厨师 publicvoidremoveObserver(WaiterObservero){ //TODOAuto-generatedmethodstub inti=waiterObservers.indexOf(o); if(i>=0) waiterObservers.remove(i); } //在此时调用通知方法 publicvoidorderChanged(){ notifyObservers(); } //接收新的定单然后通知所有服务员,以及后面厨房的厨师 publicvoidsetMeasurements(Stringorder){ this.newOrder=order; orderChanged(); } } 注释比较清楚,注册,注销函数。 接收点单,发布点单方法均为基本方法。 服务员和厨师为Observer publicinterfaceWaiterObserver{ publicvoidupdate(StringnewOrder); } 服务员A 实现两个接口,ReadOrder接口封装一个阅读点单的方法: publicclassWaiterAimplementsWaiterObserver,ReadOrder{ privateStringorder; privateManagerSubjectmanagerA; publicWaiterA(ManagerSubjectmanagerA){ this.managerA=managerA; managerA.registerObserver(this); } publicvoidupdate(StringnewOrder){ //TODOAuto-generatedmethodstub this.order=newOrder; read(order); } publicvoidread(Stringorder){ //TODOAuto-generatedmethodstub System.out.println(order); } } 特别需要说明的是,此处将chef也加到此包中。 其地位与waiterA相当。 而在一个kitchen包中运用了模板模式和简单工厂模式,对做菜的过程和菜的种类进行封装。 2.3简单工厂模式 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。 简单工厂模式又称静态工厂方法模式。 重命名上就可以看出这个模式一定很简单。 它存在的目的很简单: 定义一个用于创建对象的接口。 先来看看它的组成: 1)工厂类角色: 这是本模式的核心,含有一定的商业逻辑和判断逻辑。 在java中它往往由一个具体类实现。 2)抽象产品角色: 它一般是具体产品继承的父类或者实现的接口。 在java中由接口或者抽象类来实现。 3)具体产品角色: 工厂类所创建的对象就是此角色的实例。 在java中由一个具体类实现。 用类图可以清晰的表示它们之间的关系: 图2-8工厂模式类图 此程序中简单取一例,对牛肉运用了简单工厂模式。 publicinterfaceBeef{ publicvoidbecooked(); } 拥有一个共同的方法,被烹饪。 而后面有三种来自不同地方的牛肉分别实现此接口。 当厨师阅读菜单的时候,读到不同的牛肉,只需调用同样的becooked()方法进行烹饪。 publicclassChefimplementsWaiterObserver,ReadOrder{ privateStringorder; privateManagerSubjectmanagerA; ……………………………………… publicBeefdecidebeef(Strings){ if(s.equalsIgnoreCase("AussieBeef")) returnnewAussieBeef(); elseif(s.equalsIgnoreCase("ChineseBeef")) returnnewChineseBeef(); elseif(s.equalsIgnoreCase("JapanBeef")) returnnewJapaBeef(); returnnull; } } 而在具体的牛肉类中,关于自己被烹饪的方法又是各不相同,但烹饪的基本步骤可以抽象,因此应用模板模式进行抽象。 首先介绍一下模板方法模式: 2.4模板方法模式: 在设计模式中,模板方法是体现“求同存异”这种设计思想的典范。 “求同”就是寻求相同的地方,并且来解决它;“存异”就是搁置不同的地方,搁置的意思不是不解决,而是留待后面去解决。 模板方法模式(TemplateMethodPattern)的定义是: 一个操作中的算法的骨架,而将一些步骤延迟到子类中。 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 这里所说的算法结构,可以理解为根据需求设计出来的业务流程;而特定的步骤就是指那些可能在内容上存在变数的环节。 其中,这些在父类中实现了的步骤就是所谓的“同”,“求同”就是在父类中把相同的功能先实现;而那些延迟到子类中的步骤就是所谓的“异”,“存异”就是把不同在父类中遗留下来,到子类中去各个实现。 可以看出来,模板方法模式也是为了巧妙解决变化对系统带来的影响而设计的。 使用模板方法使系统扩展性增强,最小化了变化对系统的影响。 下面是模板方法模式的结构图: 图2-9模版方法模式结构图 请看这个模式的具体结构: 1)AbstractClass(抽象类): 定义了一到多个的抽象方法,以供具体的子类来实现它们;而且还要实现一个模板方法,来定义一个算法的骨架。 该模板方法不仅调用前面的抽象方法,也可以调用其他的操作,只要能完成自身的使命; 2)ConcreteClass(具体类): 实现父类中的抽象方法以完成算法中与特定子类相关的步骤。 在程序设计中需要对功能进行分解,对类进行细化,因为存在一个这样的原则: 单一职责原则——SRP,就一个类而言,应该仅有一个引起它的变化的原因。 因为最简单,最单纯的事情最容易控制,最有效。 类的职责简单而且集中,避免相同的职责分散到不同的类之中,避免一个类承担过多的职责;减少类之间的耦合;当需求变化时,只修改一个地方。 单一职责原则告诉我们,类的功能要单一。 这样的好处是多方面的: 第一,开发思路清晰,不容易出错。 第二,单元测试容易。 第三,代码功能简单明了,交流容易。 第四,维护容易。 根据SRP原则,上面的一个类需要用若干个类来实现,每一个类只实现一个页面的一个功能。 确立了这么一个原则,那么下面的问题就是: 我们在这些类里有很多相同的代码,怎么实现这些代码的重用呢? 将相同的代码在父类中先实现,而将不同的代码延迟到子类中实现,这就是前面所说的“求同存异”。 有了模板方法模式,既做到了满足面向对象的单一职责原则,又重用了代码。 于是将做菜的过程进行抽象,得到此抽象类: publicabstractclasskitchen{ finalvoidcookforclient(){ washmaterial(); shredder(); cook(); loadIndish(); if(clientWantsspice()){ addspice(); } } abstractvoidshredder(); abstractvoidcook(); abstractvoidaddspice(); voidwashmaterial(){ System.out.println("washthematerial"); } voidloadIndish(){ System.out.println("Pouringintocup"); } //钩子方法 booleanclientWantsspice(){ returntrue; } } 此处还运用钩子方法,对加不加香料加以控制,视客人要求而定。 一个具体实现: publicclassJapaBeefextendskitchenimplementsBeef{ @Override voidaddspice(){ //TODOAuto-generatedmethodstub System.out.print("addsomemustard"); } @Override voidcook(){ //TODOAuto-generatedmethodstub System.out.print("eatuncook"); } @Override voidshredder(){ //TODOAuto-generatedmethodstub System.out.print("doityourself"); } publicvoidbecooked(){ //TODOAuto-generatedmethodstub System.out.print("ThebeeffromJapanwillmakeyoudie"); } } 日本牛肉拥有了自己的做法,生吃! 以上及为本程序中具体运用的四个模式的说明,有对模式的理论说明还有针对本程序的实际讲解。 由于篇幅所限制,不便把所有的代码贴上,具体请参看程序代码。 三. 个人体会及建议。 1. 2. 3. 3.1个人体会 设计模式需要学习者本身对java特性有一定深度的了解和认识,起码应该熟练应用java语言。 因为基本所有模式都是建立在java语言特性上的,运用抽象类,接口,抽象方法,静态方法等等。 基本这些语言特性在java中都算难点和重点,在理解上对于新手都会存在一定的困难。 而且,个人认为,模式的学习和应用是建立在对语言特性十分熟悉的基础上,来进行一种理论上的提高和抽象。 因此觉得学习设计模式需要扎实的语言功底。 而在学习了设计模式后,的却让自己对以前头疼的代码问题找
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 面向 对象 程序设计 设计 模式 论文 邓鹏辉
![提示](https://static.bdocx.com/images/bang_tan.gif)