Head First 学习笔记.docx_第1页
Head First 学习笔记.docx_第2页
Head First 学习笔记.docx_第3页
Head First 学习笔记.docx_第4页
Head First 学习笔记.docx_第5页
已阅读5页,还剩29页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

HeadFirst 学习笔记1. 书中列举的设计原则1、封装变化。找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。2、针对接口编程,而不是针对实现编程。举例说明:假设有一个抽象类Animal,有两个具体的实现(Dog与Cat)继承Animal。“针对实现编程”的做法:Dog d = new Dog();d.bark();“针对接口编程”的做法:Animal animal = new Dog();animal.makeSound();或者:Animal animal = getAnimal();animal.makeSound();3、多用组合,少用继承。原因:a、继承会使类无限膨大,可能会使类变得臃肿。b、子类可能会继承父类中那些无用甚至有害的方法。c、组合比继承更灵活,可以实现在执行中动态改变对象的功能。4、为了交互对象之间的松耦合设计而努力。5、类应该对修改关闭,对扩展开放。6、要依赖抽象,不要依赖具体类。解释:不要让“高层组件”依赖“低层组件”,而且,不管“高层组件”还是“低层组件”,两者都应该依赖于抽象。避免违反该原则的几个方针:1) 变量不可以持有具体类的引用。如果使用new,就会持有具体类的引用,可以使用工厂来避开这种引用。2) 不要让类派生自具体类。如果派生自具体类,就会依赖具体类,可以派生自抽象或接口。3) 不要覆盖基类中已实现的方法。如果覆盖基类中已实现的方法,那么基类就不是一个真正适合被继承的类。基类中已实现的方法应该被所有子类所共享。7、最少知识原则。解释:当你设计一个系统时,不管是任何对象,你都要注意与它交互的类有哪些,并注意它和这些类是如何交互的,尽量避免过多的类耦合在一起,带来维护成本的上升。这个原则推荐的一些方针:就任何对象而言,在该对象的方法内,我们只应该调用一下范围的方法1)、该对象本身2)、被当作方法的参数而传递进来的对象3)、此方法所创建或实例化的任何对象4)、对象的任何组件。2. 策略模式先对策略模式有一个总体认识。意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。结构:下面通过鸭子模拟器的设计来具体介绍。公司需要设计一套鸭子模拟器系统,该系统的第一次需求为:鸭子能够戏水;鸭子能够呱呱叫。根据该需求系统设计如下:这个设计主要用了父类鸭子和子类绿头鸭、红头鸭,这样设计的目的是为了达到代码的复用。过了一段时间,公司希望该系统能够满足新的需求:有些鸭子会飞。因此该系统需要进行修改,修改后的系统可能如下:该系统在父类中加了“fly()”方法(在父类中加该方法是为了实现代码的复用)。这里就出现了两个问题:(1)、所有的鸭子都会飞了。(2)、所有鸭子的叫声都一样,都是“呱呱”叫。注:这两个问题可以通过子类中方法覆盖来解除,但这样处理不是很好。鸭子的类别越多,这种处理的缺点就越明显。其实这个系统的变化点是鸭子的叫声和鸭子的飞行能力,因此我们很容易想到把鸭子的叫声和鸭子的飞行能力做成接口,把这些变化的地方封装起来,这样上面的两个问题都可以解决,所以系统可能被修改为下面的样子:MallardDuck和RedheadDuck既会飞又会叫,RubberDuck只会叫不会飞,DecoyDuck不会飞也不会叫。应该说这个系统没有问题了,从表面看这种设计完全符合需求,而且完全符合面向对象的理念,但是当鸭子的类别很多时,你会发现这种设计缺乏代码的复用,这两个独立出来的接口似乎没有任何意义,根本无法减轻工作量,还不如原来的设计呢。所以你可能会想到问题的关键是接口中的方法没有实现,那我们该怎么办呢?我们的做法是把接口做成类,运用组合的方法来实现需求。考虑到“针对接口编程,而不是针对实现编程”的设计原则,我们的系统可能就会设计成如下的结构,这个结构就是应用了“策略”模式。3. 观察者模式意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。结构:例子:下面以模拟气象站系统来加以说明。需求分析:该系统的需求如下:1、气象站能够追踪目前的天气状况,包括温度、湿度、气压、2、气象站能够提供三种布告板,分别显示目前天气状况、气象统计和简单的预报。3、布告板上的数据必须实时更新。4、气象站必须提供一组API,供其他开发人员开发其他的布告板。设计部分:基于以上需求,该系统可以设计成3部分:气象站(获取实际气象数据的物理装置)、WeatherData对象(追踪来自气象站的数据,并更新布告板)和布告板(显示目前的天气状况给用户看)。效果图如下:错误的类图设计(即没有学过设计模式时的第一感觉)可能如下:相应的代码实现部分:1publicvoidMeasurementsChanged()23temperature=this.GetTemperature();/获得温度4humidity=this.GetHumidity();/获得湿度5pressure=this.GetPressure();/获得气压67MyCurrentConditionsDisplay.Update(temperature,humidity,pressure);/更新目前天气状态板8MyStatisticsDisplay.Update(temperature,humidity,pressure);/更新气象统计板9MyForcastDisplay.Update(temperature,humidity,pressure);/更新天气预报板10这个类图设计的缺点:1)、该设计是针对具体实现编程,而非针对接口。2)、对于每个新的布告板,我们都得修改代码。3)、我们无法在运动时动态得增加或删除布告板。4)、我们尚未封装改变的部分。那么如何改正这些缺点呢?首先我们必须明白这些缺点的根源在哪里。很明显,我们在类图设计时依赖关系错了,应该依赖倒置。CurrrentConditionsDisplay类、StatisticsDisplay类和ForcastDisplay类应该依赖WeatherData类,而不是相反,这样就可以起到解耦的目的。其次,CurrrentConditionsDisplay类、StatisticsDisplay类和ForcastDisplay类都有一个Update()方法,因此应该提炼一个接口,这样可以实现“针对接口编程”,使代码更加灵活,也方便其他开发人员开发其他的布告板。进一步思考:1)、改正这些缺点后,我们的类图已经与观察者模式的结构有点类似了。2)、我们的气象站系统的最大问题其实就是一对多的依赖引起的,而观察者模式正是解除一对多关系的不二法门,因此我们有必要采用观察者模式。采用了观察者模式后设计的类图应该是这样:WeatherDatea实现ISubject接口,CurrentConditionsDisplay、ForcastDisplay、StatisticsDisplay实现IObserver接口,ISubject调用IObserver,CurrentConditionsDisplay、ForcastDisplay、StatisticsDisplay调用ISubject。4. 装饰者模式意图:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。结构:例子:下面我们以星巴兹(Starbuzz)的订单系统为例加以说明。需求分析:1)、星巴兹的饮料(Beverage)种类繁多,主要有HouseBlend、DarkRoast、Decaf、Espresso。2)、星巴兹的调料很多,主要有Steamed Milk、Soy、Mocha、Whip。3)、星巴兹的饮料价格是根据饮料的基础价和所加入的调料的价格相加得到。错误设计:根据以上的简单分析,第一种类图设计出炉:其中getDescription()用来描述饮料,cost()用来计算价格。显而易见,这个类图设计的最大缺点就是类太多,系统难以维护。所以我们需要另外的解决方案,而且新方案必须避免“类爆炸”。此时我们想到了实例变量和继承。先从Beverage基类下手,加上实例变量代表是否加上调料(Steamed Milk、Soy、Mocha、Whip等),Beverage基类的cost()计算调料的价钱,而各种具体的饮料(HouseBlend、DarkRoast、Decaf、Espresso等)的cost()将把基础饮料的价钱和调料的价钱相加得到饮料的价钱。由此可以设计出第二种类图。对这个类图设计的评价:如果需求不再变化,那么这个类图设计没有错;但是需求发生了变化,这个设计就会难以招架。经过进一步的分析,我们发现部分需求被我们遗漏了。新增加的需求:1)、调料的价格可能发生变化。2)、调料的种类可能发生变化。3)、饮料的种类可能增加,不只HouseBlend、DarkRoast、Decaf、Espresso四种。4)、顾客可能在一种饮料里加双份的同种饮料。显然,第二种类图设计难以满足新的需求,而且对新增加的饮料而言,有可能存在不适合的调料。例如,茶子类将继承hasWhip()(加奶泡)等方法。因此,我们应该对类图设计进行改进。此时我们想到了装饰者模式,那么如何应用装饰者模式呢?以装饰者模式构造饮料订单:1)、以DarkRoast对象开始。2)、顾客想要Mocha,所以建立一个Mocha对象,并用它将DarkRoast对象包装起来。3)、顾客也想要Whip,所以需要建立一个Whip装饰者,并用它将Mocha对象包起来。4)、现在,该是为顾客算钱的时候了。通过最外圈装饰者(Whip)的cost()就可以办得到。Whip的cost()会先委托它装饰的对象(Mocha)计算出价钱,然后再加上Whip的价钱。根据以上的分析,应用装饰者模式,我们可以打造一个全新的类图。第三种类图设计(正确的类图):部分代码为:1publicclassDarkRoast:Beverage23publicDarkRoast()45description=DarkRoast;67publicoverridedoubleCost()89return1.22;101112publicclassMocha:CondimentDecorator1314BeveragemyBeverage;15publicMocha(BeverageparamBeverage)1617this.myBeverage=paramBeverage;181920publicoverridestringGetDescription()2122returnmyBeverage.GetDescription()+,Mocha;232425publicoverridedoubleCost()2627return0.5+myBeverage.Cost();282930classStarbuzzCoffee3132staticvoidMain(stringargs)3334BeveragemyBeverage=newEspresso();35Console.WriteLine(myBeverage.GetDescription()+$+myBeverage.Cost();3637BeveragemyBeverage2=newDarkRoast();38myBeverage2=newMocha(myBeverage2);39myBeverage2=newMocha(myBeverage2);40myBeverage2=newWhip(myBeverage2);41Console.WriteLine(myBeverage2.GetDescription()+$+myBeverage2.Cost();4243Console.ReadLine();4445装饰模式的适用情况:1)、需要扩展一个类的功能,或给一个类增加附加责任。2)、需要动态地给一个对象增加功能,这些功能可以再动态地撤销。3)、需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。使用装饰模式主要有以下的优点:1)、装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。2)、通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。使用装饰模式主要有以下的缺点:由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。5. 工厂方法模式意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。结构:实例:下面我们以Pizza店的例子来谈谈“工厂方法模式”的来龙去脉,我们学习的思路是“原始设计简单工厂工厂方法”。情景分析:假如你有一个Pizza店,那么你的Pizza订单可能会写成如下代码(这段代码写在PizzaStore类里面):1publicPizzaOrderPizza()23Pizzapizza=newPizza();4pizza.Prepare();5pizza.Bake();6pizza.Cut();7pizza.Box();8returnpizza;910如果你的Pizza店的Pizza有很多类,那么你的Pizza订单会如何写呢,可能会写成如下:1classPizzaStore23publicPizzaOrderPizza(StringparamPizzaType)45Pizzapizza=null;6if(paramPizzaType.Equals(cheese)78pizza=newCheesePizza();910elseif(paramPizzaType.Equals(greek)1112pizza=newGreekPizza();1314elseif(paramPizzaType.Equals(pepperon)1516pizza=newPepperoniPizza();1718pizza.Prepare();19pizza.Bake();20pizza.Cut();21pizza.Box();22returnpizza;232425/省略2627上面的代码有一个问题:当Pizza的种类发生改变(或增加或减少)时,这段代码必须重写。那么这段代码应该如何改进呢?其实我们只要封装变化点就行了,即代码中的“if,else”语句。封装的过程如下:1)、创建SimplePizzaFactory类。2)、在SimplePizzaFactory类中创建CreatPizza方法。3)、把“if,else”语句写道CreatPizza方法中。相应的代码如下:1publicclassSimplePizzaFactory23publicPizzaCreatPizza(StringparamPizzaType)45Pizzapizza=null;6if(paramPizzaType.Equals(cheese)78pizza=newCheesePizza();910elseif(paramPizzaType.Equals(greek)1112pizza=newGreekPizza();1314elseif(paramPizzaType.Equals(pepperon)1516pizza=newPepperoniPizza();1718returnpizza;192021这样做的好处:1)、可以很好的达到代码重用。如果其他类想得到Pizza,都可以调用SimplePizzaFactory的CreatPizza()方法。2)、维护方便。如果Pizza的创建需要改变,只需要改变CreatPizza()方法就行了,其他调用的地方不需要发生改变。值得改进的地方:可以把CreatPizza()写成静态方法。改成静态方法的优点:不需要通过创建对象来使用类里的方法。缺点:不能通过继承来改变创建对象的行为。小结:上面的代码其实是简单工厂模式的应用(简单工厂不是一个真正的模式)。简单工厂(Simple Factory)模式的意图:Simple Factory模式根据提供给它的数据,返回几个可能类中的一个类的实例。通常它返回的类都有一个公共的父类和公共的方法。结构:工厂类角色Creator (SimplePizzaFactory):工厂类在客户端的直接控制下(Create方法)创建产品对象。抽象产品角色Product (Pizza):定义简单工厂创建的对象的父类或它们共同拥有的接口。可以是一个类、抽象类或接口。具体产品角色ConcreteProduct (CheesePizza, GreekPizza,PepperoniPizza):定义工厂具体加工出的对象。客户端Client(PizzaStore):负责调用SimplePizzaFactory的Create方法。其实SimplePizzaFactory的CreatPizza()方法并没有符合面向对象的开闭原则,它没有对修改进行关闭,即当Pizza的种类改变时,这个方法必须重写,只不过改动的工作量减少了,只需要改动一处,其他调用的地方不需要变动而已。新的需求:1)、Pizza店有了加盟店,加盟店生产Pizza的流程应该一成不变。2)、每个加盟店可能要提供不同风味的Pizza(比如纽约、芝加哥、加州)。按照简单工厂的方法,我们可以这样做:创建NYPizzaFactory、ChicagoPizzaFactory、CaliforniaPizzaFactory类。相应的代码如下:1NYPizzaFactorynyFactory=newNYPizzaFactory();/创建具有纽约风味的Pizza工厂2PizzaStorenyStore=newPizzaStore(nyFactory);/建立Pizza店,经营纽约风味的Pizza3nyStore.OrderPizza(cheese);/订购具有纽约风味的CheesePizza如果需求不发生改变,那么用简单工厂就已经足够了,但是一旦需求发生了变化,简单工厂就不能适应了。变化后的需求:1)、有些加盟店采用自创的流程,比如烘烤的做法有些差异(Bake方法改变)、不要切片(Cut方法不要)、采用其他公司的盒子(Box方法改变)等。2)、Pizza的种类有可能发生改变(或增加或减少)。我们的做法很简单,具体操作:1)、把SimpleFactory的CreatPizza()方法写回到PizzaStore里面。2)、抽象PizzaStore,用NYPizzaStore、ChicagoPizzaStore等继承PizzaStore。3)、具体的PizzaStore和具体的Pizza进行一一对应。相应的类图如下(应用了工厂方法模式):说明:1)、PizzaStore类是抽象类,相当于工厂方法模式的Creator类,NYPizzaStore类和ChicagoPizzaStore类继承了PizzaStore,相当于工厂方法模式的ConcreteCreator。2)、Pizza是抽象类,相当于Product类,NYStyleCheesePizza类、NYStylePepperoniPizza类、NYStyleGreekPizza类、ChicagoStyleCheesePizza类、ChicagoStylePepperoniPizza类、ChicagoStyleGreekPizza类继承了Pizza类,相当于ConcreteProduct。3)、NYPizzaStore类调用了NYStyleCheesePizza类、NYStylePepperoniPizza类、NYStyleGreekPizza类,ChicagoPizzaStore类调用了ChicagoStyleCheesePizza类、ChicagoStylePepperoniPizza类、ChicagoStyleGreekPizza类。相应的代码如下:Code工厂方法模式的特点:1)、核心的工厂类不负责所有产品的创建,而是将具体创建工作交给子类去做,可以允许系统在不修改工厂角色的情况下引进新产品。2)、工厂类与产品类往往具有平行的等级结构,它们之间一一对应。工厂方法和简单工厂的区别:1)、Factory Method 的核心是一个抽象工厂类,而Simple Factory 把核心放在一个具体类上。2)、Factory Method 的具体工厂类都有共同的接口,或者有共同的抽象父类。3)、当系统扩展需要添加新的产品对象时,Factory Method仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放封闭”原则。而Simple Factory 在添加新产品对象后不得不修改工厂方法,扩展性不好。6. 单件模式背景:有一些对象其实我们只需要一个,比方说:线程池(threadpool)、缓存(cache)、对话框、处理偏好设置和注册表(registry)的对象、日志对象,充当打印机、显卡等设备的驱动程序的对象。事实上,这类对象只能有一个实例,如果制造出多个实例,就会导致许多问题产生,例如:程序的行为异常、资源使用过量,或者是不一致的结果。因此,我们设计这种类时必须确保只有一个实例,单件模式应运而生。单件模式的意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。结构:如何实现:其实我们只需要把构造函数私有化,把new对象的过程进行控制就行了,具体代码如下:1publicclassSingleton23privatestaticSingletonuniqueInstance;/用一个静态变量来记录Singleton类的唯一实例45privateSingleton()/构造器必须私有6789publicstaticSingletonInstance1011get1213if(null=uniqueInstance)/如果uniqueInstance为空,说明对象没有被创建1415uniqueInstance=newSingleton();1617returnuniqueInstance;18192021但是上面的代码存在一个问题。当使用多线程时,产生的对象可能不只一个,分析见下图: 如何解决这个问题:a)、使用加锁机制,具体代码如下:1publicclassSingleton23privatestaticSingletonuniqueInstance;/用一个静态变量来记录Singleton类的唯一实例4privatestaticObjectobj=newobject();56privateSingleton()/构造器必须私有78910publicstaticSingletonInstance1112get1314lock(obj)/使用加锁,避免两个线程同时进入1516if(null=uniqueInstance)/如果uniqueInstance为空,说明对象没有被创建1718uniqueInstance=newSingleton();1920returnuniqueInstance;2122232425b)、使用“急切”创建实例,不用延迟加载。具体代码如下:1publicclassSingleton23staticSingletonuniqueInstance=newSingleton();/用一个静态变量来记录Singleton类的唯一实例45privateSingleton()/构造器必须私有6789publicstaticSingletonInstance1011get1213returnuniqueInstance;14151617c)、使用“双检锁”机制。具体代码如下:1publicclassSingleton23staticSingletonuniqueInstance=null;/用一个静态变量来记录Singleton类的唯一实例4privatestaticObjectobj=newobject();56privateSingleton()/构造器必须私有78910publicstaticSingletonInstance1112get1314if(null=uniqueInstance)/先判断uniqueInstance是否为空,如果为空,再进行加锁1516lock(obj)/使用加锁,避免两个线程同时进入1718if(null=uniqueInstance)/如果uniqueInstance为空,说明对象没有被创建1920uniqueInstance=newSingleton();21222324returnuniqueInstance;25262728对上面三种方法的评价:1)、a方法采用了加锁机制,每次实例化都必须加锁,而加锁耗费的系统资源比较多,因此执行效率比较低,不推荐使用。2)、b方法书写比较简单,但没有采用延迟加载,所以可能浪费部分资源。当使用频率高且运行时负担不重时推荐使用。3)、c方法解决了多线程问题,并且只在第一次创建对象时加锁,执行效率比a方法高,推荐使用。在什么情形下使用单例模式:使用Singleton模式有一个必要条件:在一个系统要求一个类只有一个实例时才应当使用单例模式。反过来,如果一个类可以有几个实例共存,就不要使用单例模式。注意:a)、不要使用单例模式存取全局变量。这违背了单例模式的用意,最好放到对应类的静态成员中。b)、不要将数据库连接做成单例,因为一个系统可能会与数据库有多个连接,并且在有连接池的情况下,应当尽可能及时释放连接。Singleton模式由于使用静态成员存储类实例,所以可能会造成资源无法及时释放,带来问题。7. 命令模式背景:有时候我们需要对方法进行封装,通过对这些封装的方法进行调用,我们可以很好的处理一些事情。比如,记录日志,或者重复使用这些封装实现撤销功能。意图:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。结构:例子:这次我们将设计一个家电自动化遥控器的需求分析:遥控器的图:)、遥控器上具有七个可编程的插槽、七个开关按钮和一个整体撤销按钮。)、通过创建一组,使插槽可以控制一个或一组家电装置,这些装置指电灯、电风扇、热水器等。)、插槽还可以控制未来可能出现的家电装置。)、整体撤销按钮具有撤销上一个命令的功能。初步思考:)、我们将设计一系列类,这些类都具有()和()方法。)、当遥控器上的或开关被按下时,某些类的或方法被调用,进而控制家电装置,但这些被调用的类是可以被改变的(因为插槽上的东西可以改变)。)、当或开关被按下时,如果我们通过语句加以选择判断,那么第三点需求我们将难以满足。)撤销功能如何实现,上一个按钮是什么?针对的是哪一个装置?进一步思考:这次设计中不变的是遥控器(或者说是遥控器的按钮),变化的是家电装置,例如第一排开关可以控制电灯,也可以控制电风扇,或者未来可能出现的家电。所以我们需要对遥控器和家电装置进行解耦。此时我们想到了命令模式:遥控器(或者说遥控器上的按钮)就是命令的请求者,家电装置就是命令的执行者,我们所要做的就是将命令的请求者和命令的执行者解耦。具体的过程:)、客户创建命令。)、客户将命令的执行者封装进命令对象里。)、命令的请求者调用命令。)、命令的执行者执行命令。下面我们实现只有一组开关按钮的遥控器,类图如下:代码如下:1classRemoteLodder23staticvoidMain(stringargs)45SimpleRemoteControlremoteControl=newSimpleRemoteControl();6Lightlight=newLight();7LightOnCommandlightOnCommand=newLightOnCommand(light);8remoteControl.SetCommand(lightOnCommand);9remoteControl.ButtonWasPressed();10Console.ReadLine();111213publicclassLight1415publicvoidOn()1617Console.WriteLine(Lightison);181920publicvoidOff()2122Console.WriteLine(Lightisoff);232425publicclassLightOnCommand:Command2627Lightlight;2829publicLightOnCommand(LightparamLight)3031this.light=paramLight;323334publicvoidExecute()3536light.On();373839publicinterfaceCommand4041voidExecute();4243publicclassSimpleRemoteControl4445Commandslot;4647publicvoidSetCommand(CommandparamCommand)4849this.slot=paramCommand;505152publicvoidButtonWasPressed()5354slot.Execute();5556注释:命令的请求者:SimpleRemoteControl命令的执行者:Light命令接口:Command具体的命令:LightOnCommand客户(封装命令的):RemoteLodde我们的遥控器共有七个插槽,可以用数组来实现,这里不写了。撤销按钮的功能可以通过栈来实现(对Command进行入栈,出栈即可)。补充:)NoCommand模式代码:1publicclassNoCommand:Command23publicvoidExecute()456用途:当你不想返回一个有意义的对象时,就可以用空对象。客户也可以将处理null的责任转移给空对象。举例来说,遥控器出厂时可以用NoCommand对象对他进行初始化。)、宏命令代码:1publicclassMacroCommand:Command23Listcommands;45publicMacroCommand(Listcommands)67mands=commands;8910publicvoidExecute()1112foreach(Commandcommandincommands)1314command.Execute();151617用途:可以请求一次,执行多个命令。例如,按下一个按钮,实现打开电灯、电风扇、电视等功能。应用:)、队列请求想象有一个工作队列;你在某一端添加命令,然后另一端则是线程。线程进行下面的动作:从队列中取出一个命令,调用他的execute()方法,等待这个命令完成,然后将此命令丢弃,再取出下一个命令此时,工作队列类和进行计算的对象之间完全解耦。当时线程可能进行财务运算,下一刻可能读取网络数据。)、日志请求这需要我们将所有的动作(命令)记录在日志中,并能在系统死机后,对这些命令对象重新加载,成批的依次调用这些对象的execute()方法,恢复到之前的状态。比方说,对于电子表格的应用,我们可能想要实现的错误恢复方式是将电子表格的操作记录在日志中

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论