以生活中的例子快速理解十个设计模式

缘由

这是我软件工程考试复习时制作的。


观察者模式

如果朋友来你家玩,他坐公交来,你需要在合适的时间到附近的车站去接他。我们就是观察者,朋友就是被观察者。我们可以一直打电话问朋友,这就是观察者一直去询问被观察者,也可以被观察者到了合适的时候主动通知观察者。显然第二种更为合理。

如下图所示,在合适的时候,被观察者subject就会执行notifyObserver,里面会依次调用Observer的update方法。

 

状态模式 

参考博客:http://blog.csdn.net/hguisu/article/details/7557252

这个博客本来已经讲的很棒的了,结果就是因为对名字的取法有点错误,导致我差点没理解了。在物品拥有的状态这个过程中,Context应该就是物品。例子比如电梯(图中context)有4种状态,运动、停止、开门、关门。在不同状态间切换时,必须先知道目前处于什么状态,比如要是开门状态就不能运动。所以必须使用很多if-else。但是使用状态模式就不用了,状态模式将不同的状态用类来表示。如图所示,注意context里面其实是有一个成员变量是currentState。


 

桥接(Bridge)模式

它主要应对的是:由于实际的需要,某个类具有两个或两个以上的维度变化,如果只是使用继承将无法实现这种需要,或者使得设计变得相当臃肿。
关键在于面有分为辣不辣的牛肉面还是猪肉面的,我们可以做4个子类来显示辣椒牛肉面、无辣牛肉面、辣椒猪肉面、无辣猪肉面。不过如果以后增加了呢?增加了羊肉面、鸡肉面,辣再来个超级辣,辣也不够用了,直接来个酱香味的口味(说的肚子都饿了)。难道还有用组合的弄出那么多子类吗?
答案就是桥接模式帮我们解决了这个问题。对于一碗面,风味(辣不辣)和材料(猪肉、牛肉)是两个不同的变化方向,或者说是维度,为了能够满足多维度的变化,以及其变化的多样性。我们使用了桥接模式。
关键就是:
有一个接口 叫风味,风味有个方法,我们可以自己用个类来继承风味接口实现这个风味方法(辣不辣)。所以我们可以定义一个辣的风味类,来实现辣的方法。
抽象面类有一个成员,就是风味接口的实现类,并且设定在构造方法内必须指定风味的对象。面当然主要功能就是被吃,所以还是一个吃方法。
接着牛肉面继承面,猪肉面也继承了面,牛肉面完成了自己的吃方法,猪肉面也完成了自己的吃方法。
现在当我们要实例化一个牛肉面类时,必须要传入一个风味对象,具体是什么就看看官口味了。我们new 风味对象的实体类传进去即可。
 

很模糊,但是大概懂了的意思就行了。还有一附图:


复合(Composite)模式

参考博客:http://www.blogjava.net/alex/archive/2006/09/08/68627.html
复合对象是包含了其它对象的对象。例如,一幅图由一些基本的对象组成,例如线、圆、矩形和文本等,因此图就是复合对象。因为在Java 中,开发人员操作基本对象的方式和操作复合对象的方式常常相同,因此需要利用到复合模式。例如,线或文本等基本图形对象都需要支持绘制、移动或缩放等功 能;而图这种复合对象也需要支持相同的功能。在理想的情况下,我们希望对复合对象和基本对象以完全相同的方式完成这些操作,否则实现的代码将会产生不必要 的复杂性,并且不易于维护和扩展。
那么什么是复合模式呢?将对象组织到树结构中以表达部分整体的层次关系就实现了复合模式,它使程序能够以相同的方式对待基本对象和复合对象。
在程序中实现复合模式并不难。复合类继承一个代表基本类型的基类就可以了 。图1显示了一个表现复合模式思想的类图。


针对Component类中的每个方法,Composite类都有相同名称的方法 与之对应。Composite类保存了一个基本对象的集合。通常Composite类中的方法在实现时都会将集合中的对象遍历一次,然后调用每个对象中相 应的方法。例如图对象Drawing的draw()方法可能是这样实现的:
//  代码1一个复合方法 
public   void  draw() {
    //  I遍历所有的对象 
    for ( int  i = 0 ; i  <  getComponentCount();  ++ i) {
       //  获得对对象的应用,调用它的draw方法 
      Component component  =  getComponent(i);
      component.draw();   
   }
 

简单工厂模式

简单工厂模式(Simple Factory Pattern)属于类的创新型模式,又叫静态工厂方法模式(Static FactoryMethod Pattern),是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

比如说在披萨店吃饭,食物有培根披萨、芝士披萨,客人去点餐。那么披萨店就是一个工厂,培根披萨和芝士披萨都属于抽象类食物的实现类,客人点餐就直接告诉披萨店这个工厂,这个工厂会负责生产食物,其实也就是初始化具体的实例对象:培根披萨和芝士披萨,然后返回给客人。一般来说抽象类食物有自己的抽象方法,实现类对必须去实现。(这样公共的实现类)





工厂方法模式
参考博客:http://www.cnblogs.com/zzj-46000452/archive/2006/09/16/506286.html
继续上面的例子,现在需要在全国各地开不同的分店。分店也有自己的特色,比如四川就会多放点辣椒。所以,工厂方法就是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。披萨店是一个抽象类,四川披萨店是其子类,其实现了创建食物的具体方法:加辣培根披萨、加辣芝士披萨。也可以有别的很多工厂子类。原来我在开发安卓软件就可以为该app设定背景主题风格。那就是使用了工厂方法。


建造模式

参考博客:http://www.cnblogs.com/BeyondAnyTime/archive/2012/07/19/2599980.html
建造者模式(Builder):是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。一定要注意,是一个对象的建造过程很复杂,才产生了这个设计模式的出现。

一共需要4个类(接口):
  1. 接口builder,里面规定为了产生一个对象必须要要的组成部分。
    比如一个假期对象,这个假期包含(抽象方法):耍几天、住什么旅馆、吃什么饭、参加什么特别活动。
  2. 接着是ConcreteBuilder,这是接口builder的实现类,在这个实现类里面实现了抽象方法,所以就规定好了耍2天,住希尔顿宾馆,吃工作餐,参加篝火晚会。这就是一个假期的具体实现。
  3. 有一个Director类,有一个Construct方法,创建假期。Construct会调用根据传入的具体的ConcreteBuilder的对象,来与ConcreteBuilder对象相对应的假期。builder还规定了一个返回假期的函数。那么就返回了ConcreteBuilder具体的创建的假期。
  4. Product类:在这里就是假期,成员属性就有刷的天数、旅馆名、套餐名、特别活动名。
 
这里例子是head first 设计模式书上的,但是我觉得博客里面的创建小人的例子说的更清楚一些。关联关系的一种,是强的关联关系。聚合关系是整体和个体的关系。另一个个体可以单独存在。车与轮子的关系。


适配器(Adapter)模式

http://zy19982004.iteye.com/blog/1415735
键盘的插口是PS2接口的,但是我想让这个键盘在我的笔记本电脑上使用。笔记本电脑没有PS2接口,我就买了一个转接器。对于我的键盘来说,是需要ps2接口,转接器就将笔记本的usb接口转成了ps2接口,让我的键盘插。换句话,就是现在只供应usb接口,但是客户需要ps2接口,所以需要适配器将usb接口转为ps2接口满足客户需求。其实说白了两种适配器都很简单了。下面这个对象适配器。适配器USBToPS2有一个对象usbPort,所以可以以usb的方式工作:workWithUSB()。现在我们要外部要其以workWithPS2的方式工作。注意继承了PS2Port的接口,其实是内部调用了workWithUSB()而已。
public class USBToPS2 implements PS2Port{ 
private USBPort usbPort;  
public USBToPS2(USBPort usbPort) {  
        this.usbPort = usbPort;  
    } 
    public void workWithPS2() {  
        USBPort.workWithUSB();   
    } 
}  

这是对象适配器,而对象适配器是用委派关系。图如下所示:


类适配器是用多继承来实现的。原来差不多。

public class PS2ToUSB implements USBPort, PS2Port{  
    //重写workWithUSB,把工作交给workWithPS2  
    @Override  
    public void workWithUSB() {  
        workWithPS2();  
    }  
}  


装饰(Decorator)模式

参考博客:http://blog.csdn.net/zy825316/article/details/23794263
博客里写过了,但是我还想这里用最短的几句说一下。吃面的时候,可以单点牛肉面、猪肉面。如果但是又可以加鸡蛋,加肉丸,组成鸡蛋猪肉面。如果要开发这个系统的时候,面很多,附加食品也多。就会很难计算。
装饰模式,就是说有一个面的抽象类(抽象方法cost()返回价钱),牛肉面、猪肉面作为实现类(cost返回各自价钱),继承于面。再一个的抽象类Decorator(),也继承于面,所以也有方法cost(),它还有一个成员变量就是面。再制作Decorator()的实现类(加鸡蛋),那么在生成这个实现类的时候必须要传入一个面的对象,就是被装饰的对象,再在其cost()方法里面返回面的价钱+鸡蛋的价钱。所以我们可以再把这个Decorator()的实现类(加鸡蛋)再被装饰一遍,也就是传入另一个第二个Decorator()的实现类(加鸡蛋)的对象,那么就相当于加了两个鸡蛋。那么加个丸子也不在话了。
定义:装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。


策略(Strategy)模式

http://blog.csdn.net/zy825316/article/details/23476099
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户(下面的鸭子就是客户)而独立变化。
下面的例子中叫的一组是一系列算法,飞的一组是另一系列的算法。
游戏里,有很鸭子,我们可以先作一个抽象类,全部继承这个鸭子。但是鸭子的变化很多,有的鸭子可以吱吱叫,有的嘎嘎叫,有的鸭子不能叫。关于飞,有的跳着飞、有的低空飞、有的高空飞。所以关于飞和叫,是两种不同的行为组,我们定义两个接口(接口有抽象方法叫或者飞)。下面以叫为例,吱吱叫继承叫的接口,作为一个实现类。嘎嘎叫继承叫的接口,作为另一个实现类。对于一个鸭子,有一个成员属性就是叫,并且有set和get方法。那么我想让鸭子叫的时候,直接调用接口叫的抽象方法叫就可以了。因为set已经为我动态绑定了一个叫的实现类。

模板方法

参考博客:http://blog.csdn.net/lenotang/article/details/2911246
模板方法Gof的定义是:在一个方法里定义算法的骨架,将一些步骤延迟到其子类。
AbstractClass主要是定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。TemplateMethod 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
我们来看一个模板方法的应用 
  假设教育部规定了高校新生报到的流程(这好比写好了算法的骨架),流程为凭录取通知书到教务处报到->缴费->本院系报到(获取自己的专业班级信息)->教材科领取教材。但是各个大学可以根据自己的需求来规定每一步需要完成的事,比如教务处报到()的时候,有一个大学要求拿着录取通知书和身份证报告,另一个大学只录取通知书就可以了。又比如一个大学缴费的时候只收取现金,另一个大学只能刷卡。但是他们报告的流程是不能变的,报告的流程就是模板方法。

public class 高校
{
//这就是一个模板方法,定义了算法的骨架
public final void 报到()
{
教务处报到();
缴费();
本院系报到();
教材科发教材();
}
protected abstract void 教务处报到();
protected abstract void 缴费();
protected abstract 专业等信息 本院系报到();
protected abstract 教材 教材科发教材();
}




责任链模式

责任链模式:chain of responsibility pattern 当你想让一个以上的对象有机会处理某个请求的时候,就使用责任链模式。
试想,在公司要请假,首先肯定是给自己的直属领导,比如就是项目经理,如果项目经理批了那就算请到了。但是请假的天数太长,项目经理发现自己决定不了,就想去问问自己的直属领导,就叫项目总监吧,项目总监发现在自己的权限范围以内,可以批也就批了。但是还是处理不了呢?那么就得又叫给自己的直属领导,就当是:总经理吧。总经理一般是最大的了,总经理决定批了,那假也就准了,如果不批,这事也算完了。
Ok,这里关键就是,请假人,他只需要知道自己要请假,找项目经理就可以了,不用管项目经理具体会怎么做。而最后请假人得到的消息必然是:准假或者不准假。但是这个准假可能来自项目经理、项目总监、总经理。都有可能。但是请假人并不需要知道这些细节。
试想有遇到了这样的情况,公司的管理发生了改变,如果项目经理决定不了的请假的事宜,比如大于1天,需要交给人事部门,人事部门决定无法决定的再交给项目总监。那么我只需要把项目经理的后继者该懂以下即可。

后记

为了复习这个考试的全部文档在,已经上传网盘:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值