设计模式(二)

    技术2022-05-13  0

    6 The Command Pattern encapsulates a request as an object,thereby letting you parameterize other objects with different requests ,quequ or log requests,and support undoable operations.这个模式把请求封装到一个类中,因此你可以用这个请求当函数参数,还可以方便的记录请求列表(也就是操作日志),也可以方便的实现undo操作。光看这个定义可能不太理解,我们还是来看例子。现在我想设计一个万能遥控器,上面有15个按钮,我希望可以通过这些按钮来控制家里的各种电器的操作,比如打开电灯,关闭电灯,打开车库门等等,因为不同的电器可以进行的操作各不相同,也不都是简单的开和关两种操作,而且,我家里可能经常性的增加或者更换设备,因此我希望设计的遥控器能够很方便的修改和扩展。那我怎么能通过使用这个模式来解决问题呢?可以分析一下它的定义,把命令封装成一个物体,从这里入手,我们可以定义一个抽象的类command,所有的具体命令都由它继承,这样所有的命令都有了一个一致的接口,我们在这个command类中增加一个execute()方法,调用具体命令时我只需要调用这个方法即可,而不用关心具体调用的是什么命令,这样我们可以把遥控器上的每一个按钮设置一个command对象,按下的时候会自动调用该对象的execute()方法,而需要改变时,只需对这个按钮重新赋一个command对象即可。下面是代码实现:

    public interface Command{ public void execute(); } public class LightOnCommand implements Command{ Light light; public LightOnCommand(Light light){ this.light=light; } public void execute(){ light.on(); } } public class LightOffCommand implements Command{ Light light; public LightOnCommand(Light light){ this.light=light; } public void execute(){ light.off(); } } public class StereoOnWithCDCommand implements Command{ Stereo stereo; public StereoOnWithCDCommand(Stereo stereo){ this.stereo=stereo; } public void execute(){ stereo.on(); stereo.setCD(); stereo.setVolum(11); } } public class NoCommand implements Command{ public void execute(){ //do nothing } } //you could add any commands you want here public class RemoteControl{ Command[] onCommands; Command[] offCommands; public RemoteControl(){ onCommands=new Command[7]; offCOmmands=new Command[7]; Command noCommand=new NoCommand(); for(int i=0;i<7;i++){ onCommand[i]=noCommand; offCommand[i]=noCommand; } } public void setCommand(int slot,Command onCommand,Command offCommand){ onCommands[i]=onCommand; offCommands[i]=offCommand; } public void onButtonWasPushed(int slot){ onCommands[i].execute(); } public void offButtonWasPushed(int slot){ offCommands[i].execute(); } } public class test{ public static void main(String[] args){ RemoteControl remoteControl=new RemoteControl(); Light livingRoomLight=new Light("Living room"); Stereo stereo=new Stereo("Living room"); LightOnCommand livingRoomLightOn=new LightOnCommand(livingRoomLight); LightOffCommand livingRoomLightOff=new LightOffCommand(livingRoomLight); StereoOnWithCDCommand stereoOnWithCD=new StereoOnWithCDCommand(stereo); StereoOffCommand stereoOff=new StereoOffCommand(stereo); //....... add your commands here //set the command to the remote control remoteControl.setCommand(0,livingRoomLightOn,livingRoomLightOff); remoteControl.setCommand(2,stereoOnWithCD,stereoOff); //......set other commands //test the romoteControl remoteControl.onButtOnWasPushed(0); remoteControl.onButtOnWasPushed(3); } } 我们再来回看一下这个模式,它的作用实际是把请求的发送者和接受者分离开来,举个例子来说,人要打开一盏灯,那么人是请求的发送者,而灯是请求的接受者,如果直接写程序的话必然要求这两个对象进行直接的交互,而现在,我们通过LightOnCommand类,将命令和recerver都封装到这个类中,这样,接受者和发送者不用直接打交道,我们可以创立一个单独的对象来管理所有的命令(在这个例子中,就是RemoteControl类),这给很多操作提供了便利,我们来讨论几个这个模式的实际应用场景。在操作系统中,很多进程都有系统调用的命令,而如果每个进程都直接和管理系统资源的进程直接打交道,这会导致管理或实现机制非常的复杂,而现在的操作系统一般是实现一个命令队列,进程有系统调用请求的时候,只需把请求命令加入到命令队列里,而管理系统资源的进程也不需要考虑当前有多少进程在请求资源,它只需要从命令队列里按顺序取出并执行命令即可,这大大简化了实现和维护的难度。又比如,现代操作系统都支持日志的功能,所谓日志就是记录进程都执行了什么命令,如果每个命令都有一个store()方法,那记录日志就很简单,只需在执行完每个命令后调用它的store()方法即可,同理,可以根据记录的日志恢复异常中断的进程,还可以方便的实现undo操作等等。扩展后的Command接口如下所示:

    public interface Command{ public void execute(); public void undo(); public void store(); } public class LightOnCommand implements Command{ Light light; public void LightOnCommand(Light light){ this.light=light; } public void execute(){ light.on(); } public void undo(){ light.off(); } public void store(){ //log "LightOnCommand" to a specific file } }

     

    7 the Adapter and Facade Pattern:

       The Adapter Pattern converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interface.这个模式说穿了非常的简单,就是说现有的类和以前的类不兼容,我们不希望改变过去的类,有希望现在的类能和过去的类有一个统一的接口,这时候我们提供了一个类似adapter的类来实现这个目标。举个例子,现在有一群鸭子在池塘里捕鱼,后来又飞过来一只鹅,这只鹅也希望到池塘里捕鱼但又怕与鸭子冲突,于是它就把用一个adapter把自己伪装成一只鸭子,这样就可以与鸭子一起捕鱼了,我们来看看这个实现吧:

    public interface Duck{ public void quack();//sound of ducks public void fly();// } public interface goose{ public void gobble();//sound of goose public void fly(); } public class MallardDuck implements Duck{ public void quack(){ System.out.println("Quack"); } public void fly(){ System.out.println("MallardDuck flying"); } } public class wildGoose implements goose{ public void gobble(){ System.out.println("goose gobble"); } public void fly(){ System.out.println("goose flying"); } } public class GooseAdapter implements Duck{ goose goo; public GooseAdapter(goose goo){ this.goo=goo; } public void quack(){ goo.gobble(); } public void fly()[ goo.fly(); } } public class DuckTestDrive{ public static void main(String[]args){ MallardDuck duck=new MallardDuck(); goose goo=new willdGoose(); Duck GooseAdapter =new GooseAdapter(turkey); test(duck); test(GooseAdapter); static void test(Duck duck){ duck.quack(); duck.fly(); } } }

    很简单吧,这就是所谓的Adapter Pattern ,它使得一个接口可以通过adapter变成另外一种接口,很形象的一个例子就是我们的充电器,有时候接口是不一样的,所以好多公司就提供一个adapter,他们负责把一个接口换成另一个接口。

    The Facade Pattern provides a unified interface to a set of interfaces in a subsystem.Facade defines a higher-level interface that makes the subsystem easier to use.这个模式是通过抽象底层的复杂接口,给用户提供一个简单的高层接口,比如家里的影院设备,如果我想看电影,我需要打开vcd,插入光盘,打开音响,调好音量和室内的光线等等一系列的操作,那我就可以在这个接口上面再抽相处一个简单的operate接口,里面有一个方法start(),这个方法里就包括了上述的所有操作,对用户提供了一个更简单的接口,这就是这个模式的用处,这里就不再详细介绍。

     

    8 The Template Method Pattern defines the skeleton of an algorithm in a method,deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.这个模式是说在一个方法中定义一个算法的基本框架,里面有些步骤需要在子类中实现,子类可以根据具体的情况对一些步骤进行扩展或改变,但是算法整体的框架是不变的,说穿了,又是多态技术。考虑一个例子,泡茶有四个步骤组成,分别是1 boil some water 2 steep the teabag in the water 3 pour tea in a cup 4 add lemon ,而泡咖啡也有四个步骤,分别是1 boil some water 2 brew the coffee grinds  3 pour coffee in a cup 4 add sugar and milk 可以看出来,这两种方法大致上的结构是一样的,但是细化到每一步又有一些差别,这就是这个模式的应用场景,在父类的模板方法中实现算法的基本框架,而在子类中细化其中的某些步骤,我们来看一下实现代码:

    public abstract class CaffeineBeverage{ void prepareRecipe(){ boilWater(); brew(); pourInCup(); addCondiments(); } abstract void brew(); abstract void addCondiments(); void boilWater(){ System.out.println("Boliing water"); } void pourInCup(){ System.out.println("Pouring into cup"); } } public class Coffee extends CaffeineBeverage{ public void brew(){ System.out.println("Dripping Coffee through filter"); } public void addCondiments(){ System.out.println("adding Sugar and milk"); } } public class Tea extends CaffeineBeverage{ public void brew(){ System.out.println("Dripping tea "); } public void addCondiments(){ System.out.println("adding lemon"); } } public class Test{ public static void main(String[] args){ Tea tea=new Tea(); Coffee coffee=new Coffee(); tea.prepareRecipe(); Coffee.prepareRecipe(); } }这个模式用来确定一个算法的大致框架,但又给子类提供了在某些具体步骤进行改变的便利,这个模式大家可能编程的时候都用到过,只是不知道它还有这么个专业化的名字而已。

     

    9  the iterator and composite patterns:之所以把这两个模式放到一起,是因为它们都是针对集合类的设计模式。很多时候,我们都需要遍历集合类中的元素,而我们并不关心内部用的是数组,集合,hash表还是什么,我们只需要有一个接口,它能够遍历一下集合类中的所有元素即可,这就是iterator pattern 的来源和用处。The Iterator Pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.定义也就是说这个模式提供了一个遍历集合对象的方法,但又不暴露内部的具体实现方法,我们来看一个简单的实现:

    public interface iterator{ public boolean hasNext(); public Object Next(); } public arrayIterator implements iterator{ ArrayList array; int position; public void arrayIterator(ArrayList arrayNew){ array=arrayNew; position=0; } public boolean hasNext(){ if(position<array.length()) return true; else return false; } public Object Next(){ return array[i]; } } public class allNameInClass { ArrayList nameArray; public allNameInClass(){ nameArray=new ArrayList(); } public void addName(String name){ nameArray.add(name); } public iterator createIterator(){ return new arrayIterator (nameArray); } } public class test{ public static void main(String[] args){ allNameInClass testing=new allNameInClass (); testing.addName("zhou"); testing.addName("wang"); testing.addName("zhang"); iterator it=testing.createIterator(); while(iterator.hasNext()){ String temp=(String)iterator.Next(); System.Out.println(temp); } } } 以上代码就是一个简单的iterator模式的实现,用户无需考虑类的内部表示就能遍历其中的所有元素,一来给用户提供了统一的接口,因此增加了方便性;二来对类的设计者提供了某种保护机制,因为内部表示外面无法知道,因此增强了安全性。

    The Composite Pattern :allows you to compose objects into tree structure to represent part-whole hierarchies.Composite lets clients treat individual objects and compositions of objects unformly.这个模式把对象组织成一个树的结构,某个节点或者是叶子节点,或者是一个子树,它们有统一的共同接口。它的便利性体现在用户可以对任意一部分,对整体,对单个个体进行研究,而操作的接口都是一样的,我们还是来看一个例子,这是一个饭店菜单的设计,菜单有很多项,项可以是某个具体的条目,也可以是一个子菜单,它们有一个共同的接口,看一下实现代码:

    public abstract class MenuComponent{ public void add(MenuComponent menuComponent){ throw new UnsupportedOperationException(); } public void remove(MenuComponent menuComponent){ throw new UnsupportedOperationException(); } public void getChile(int i){ throw new UnsupportedOperationException(); } public String getName(){ throw new UnsupportedOperationException(); } public String getDescription(){ throw new UnsupportedOperationException(); } public double getPrice(){ throw new UnsupportedOperationException(); } public void print(){ throw new UnsupportedOperationException(); } } public class MenuItem extends MenuComponent{ String name; String description; double price; public MenuItem(String name, String description,double price){ this.name=name; this.description=description; this.price =price; } public String getName(){ return name; } public String getDescription(){ return description; } public double getPrice(){ return price; } public void print(){ System.out.println(""+getName()); System.out.println(","+getPrice()); System.out.println(",",getDescription()); } } public class Menu extends MenuComponent{ ArrayList menuComponents =new ArrayList(); String name; String description; public Menu(String name,String description){ this.name=name; this.description=description; } public void add(MenuComponent menuComponent){ menuComponents.add(menuComponent); } public void remove (MenuComponent menuComponent){ menuComponents.remove(menuComponent); } public String getName(){ return name; } public String getDescription(){ return descriprion; } public void print(){ System.out.println("/n"+getName()); System.out.println(","+getDescription()); System.out.println("-----------------"); Iterator iterator=menuComponets.iterator(); while(iterator.hasNext()){ MenuComponent menuComponent=(MenuComponent)iterator.next(); menuComponent.print(); } } } public class Waitress{ MenuComponent allMenus; public Waitress(MenuComponent allMenus){ this.allMenus=allMenus; } public void printMenu(){ allMenus.print(); } } public class test{ public static void main(String args[]){ //add some MenuComponent breakfast=new Menu("breakfast","breakfast" ); MenuComponent lunch=new Menu("lunch","lunch"); MenuComponent supper=new Menu("supper","supper"); MenuComponent allMenus=new Menu("all Menus","all menus"); allMenus.add(breakfast); allMenus.add(supper); allMenus.add(lunch); breakfast.add(new MenuItem("fooda","pasta",2.3)); supper.add(new MenuItem("foodb","pasta",2.3)); lunch.add(new MenuItem("foodc","pasta",2.3)); Waitress waitress=new Waitress(allMenus); waitress.printMenu(); } } 其实就是一个树结构的实现,使叶子节点和中间节点有了一个统一的接口,方便用户使用。

     

    10 The State Pattern allows an object to alter its behavior when its internal state changes.The object will appear to change its class.顾名思义,这个模式是把一个状态封装到一个类中,为什么要这么做呢,考虑一个常见的状态机问题,一个物体可以有很多状态,也有很多方法,在某种状态下调用某种方法会导致物体从一个状态变到另一个状态,如果所有状态都在一个类中,我们可以想象导致状态发生变化的方法肯定是这样实现的:

     if(state==a)

       dosometing();

     else if (state==b)

       dosomething();

      else if(state==c)

       dosomething();

    ............

    可能物体有很多的状态,我们需要把所有的列举出来,一旦增加或减少一个状态,需要在所有的方法中都进行修改,这显然不是一个很好的设计,我们希望增加或减少状态时只会影响到跟这个状态有直接关系的少数几个状态,而不是所有的状态,我们看看这个模式怎么来解决这个问题,看一个自动售货机的例子,代码如下:

    public interface State{ public void insertQuarter(); public void enjectQuarter(); public void turnCrank(); } public class NoQuarterState implements State{ GumballMachine gum; public NoQuarterState(GumballMachine machine){ this.gum=machine; } public void insertQuarter(){ System.out.println("some tips"); gum.setState(gum.getHasQuarterState()); } public void enjectQuarter(){ System.out.println("some tips"); } public void turnCrank(){ System.out.println("some tips"); } } //implements other state class here public class GumballMachine{ State soldOutState; State noQuarterState; State hasQuarterState; State soleState; State state=soldOutState; int count=0; public GumballMachine(int numberGumballs){ soldOutState=new SoldOutState(this); noQuarterState=new NoQuarterState(this); hasQuarterState=new HasQuarterState(this); soldState=new SoldState(this); this.count=numberGumballs; if(count>0){ state=noQuarterState; } } public void insertQuarter(){ state.insertQuarter(); } public void enjectQuarter(){ state.enjectQuarter(); } public void turnCrank(){ state.turnCrank(); } void setState(State state){ this.state=state; } void releaseBall(){ System.out.println("ball is coming"); if(count!=0){ count=count=1; } } }   代码里只实现了一个状态,其他的可以模仿着进行实现,是否发生状态转移要视具体情况而定,在实现这个模式时,要先在纸上把状态图画出来,要不然很容易出错。这个模式就是把每一个状态封装成一个类,通过设定使用者不同的状态,使用者可以表现出不同的行为。

        书的后面介绍了proxy模式,就是代理的意思,比如提供一个网络代理,你只需同代理打交道,代理负责处理跟网络有关的细节信息,这个模式看的不是很懂,而且我感觉跟java结合太紧了,里面用到了好多java独有的机制,以后有机会再好好研究一下。还有一个复杂compound pattern ,就是把前面学过的各种模式综合到一块,最后又讲了一下MVC,一个比较成功的compound pattern,本书也就到此结束了,如果还想继续钻研设计模式,可以看完本书后再去看四人帮那本经典的设计模式教程。

     


    最新回复(0)