1、软件设计模式复习题1、 熟悉每个设计模式的定义、模式UML图解、模式使用情形以及模式优缺点。2、 设计模式的两大主题是什么?3、 设计模式分成几大类?每大类各包含哪些模式?4、 为什么要使用设计模式?使用设计模式有哪些好处?5、 比较抽象工厂模式和工厂方法模式相似性和差异性。什么情况下使用抽象工厂模式?什么情形下使用工厂方法模式?6、 简述原型模式中浅层克隆和深度克隆的区别?分别给出代码说明。7、 模板方法和普通的实现类继承抽象类方式有何区别?8、 是比较和分析适配器模式和桥接模式之间的共性和差异性。9、 请用组合模式实现学校人事管理模式。10、 综合应用装饰模式、命令模式和状态模式实现工具条
2、命令按钮鼠标进入时高亮显示状态以及鼠标单击按钮后呈现凹陷状态,表明当前按钮为选中状态。11、 请阐述享元模式是如何节省系统内存的?试举例分析使用享元模式前后的内存节约之比。12、 使用解析器模式实现对学生成绩表的查询输入语句进行解析并执行查询,成绩表结构如下:学号姓名专业班级课程代码课程名称课程性质任课教师成绩13、 结合命令模式和备忘录模式实现程序的undo和redo功能。14、 试比较和分析中介者模式和观察者模式之间的相似性和差异性?两者是否能够相互转化?15、 模板方法和普通的抽象类继承有什么区别?16、 使用访问者模式对12题中的学生信息进行报到。1、 熟悉每个设计模式的定义、模式UM
3、L图解、模式使用情形以及模式优缺点。(见书)答: 单件模式:单例模式:class Singletonprivate static Singleton instance; private Singleton() public static Singleton GetInstance()if (instance = null) instance = new Singleton(); return instance; 客户端代码:class Programstatic void Main(string args) Singleton s1 = Singleton.GetInstance(); Sin
4、gleton s2 = Singleton.GetInstance(); if (s1 = = s2) Console.WriteLine(Objects are the same instance); Console.Read(); 多线程时的单例(Lock是确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放)class Singletonprivate static Singleton instance; private static readonly object syncRoot = new objec
5、t(); private Singleton() public static Singleton GetInstance()lock (syncRoot) if (instance = null) instance = new Singleton(); return instance ; 双重锁定:不用让线程每次都加锁,而只是在实例未被创建的时候再加锁处理。同时也能保证多线程的安全性。class Singletonprivate static Singleton instance; private static readonly object syncRoot = new object();
6、private Singleton() public static Singleton GetInstance()if (instance = null) lock (syncRoot) if (instance = null) instance = new Singleton(); return instance;静态初始化:不需要开发人员显示地编写线程安全代码,即可解决多线程环境下它是不安全的问题。public sealed class Singleton private static readonly Singleton instance=new Singleton(); private
7、 Singleton() public static Singleton GetInstance()return instance; 组合模式:l 透明方式:在Component中声明所有用来管理子对象的方法,其中包括Add、Remonve等。这样实现Component接口的所有子类都具备了Add和Remove。这样做的好处就是叶节点和枝节点对外界没有区别,他们具备完全一致的行为接口。l 安全方式:在Component接口中不去声明Add和Remove方法,那么子类的Leaf也就不要去实现它,而是在Composite声明所有用来管理子类对象的方法。由于不透明,客户端要做判断。外观模式:创建AD
8、O.NET的Faade2、 设计模式的两大主题是什么?答:对象组合,类继承的讨论3、 设计模式分成几大类?每大类各包含哪些模式?答:模式大体上分为3类,分别从对象的创建、对象的结构和对象的行为这3个方面来总结软件开发人员在设计方面的经验。(1)创建型模式单件模式(Singleton):单例模式确保某一个类有且仅有一个实例,并且提供了一个全局的访问点,切自行实例化并向整个系统提供这个实例。抽象工厂模式(Abstract Factory):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。(抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个
9、抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据LSP原则,任何接受父类型的地方,都应当能够接受子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。)建造者模式(Builder):将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立地变化,客户不必知道产品内部组成的细节。建造模式可以强制实行一种分
10、步骤进行的建造过程。工厂方法模式(Factory Method):抽象工厂类负责定义创建对象的接口,具体对象的创建工作由实现抽象工厂的具体工厂类来完成。工厂类不再负责所有产品的创建,而是将具体的创建工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。原型模式(Prototype):通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。(没有的)简单工厂模式(Simple Factory):定义一个具体的工厂类来负责创建一些类的实例,而这些被创建的类都应该有一个共同的父类,这样就可以实
11、现面向抽象而不是面向具体编程。客户类和工厂类分开,客户类任何时候需要某种产品,只需向工厂请求即可,客户类无需修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。(2)结构型模式适配器模式(Adapter):把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。(将类自己的接口包裹在一个已存在的类中。)桥接模式(Bridge):将抽象化与实现化脱耦,使得两者可以独立地变化,也就是指在一个软件系统的抽象化和实现化之间使用组合关系而不是继承关系,从而使两者可以独立地变化。装饰模式(Decorator):装饰模式以对客户端透明的方式扩
12、展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。(装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。)组合模式(Composite):用来描述整体与部分的关系,组合模式使得客户端把一个个单独的成分对象和由它们复合而成的合成对象同等看待。(有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。 )外观模式(Facade):为子系统对外提供的一组接口提供一个统一的界面,使得其他系统对该系
13、统的访问都通过这个统一的界面来完成。享元模式(Flyweight):享元模式以共享的方式高效地支持大量的细粒度对象,享元模式能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部,不会随环境的改变而有所不同。外蕴状态是随环境的改变而改变的,享元模式大幅度地降低内存中对象的数量。代理模式(Proxy):代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。(3)行为型模式模板方法模式(Template Method):定义一个算法执行的骨架,而将具体的算法延迟到子类中来实现。命令模式(Command):命令模式把一个请求或者操作封装到一个对象中,命令模式把发出命令的责任
14、和执行命令的责任分割开,委派给不同的对象。(将一组行为抽象为对象,实现二者之间的松耦合。)迭代器模式(Iterator):可以顺序访问一个聚集中的元素而不必暴露聚集的内部表象。(分离了集合对象的遍历行为,抽象出一个迭代器来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据。)观察者模式(Observer):让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。(在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”-一个对象(目标对象)的状态发生改变,所有依赖对象(观察者对象)都将得到通知。如果
15、这样的依赖关系过于紧密,将使软件不能很好地抵御变化。使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。)解释器模式(Interpreter Pattern):解释器模式属于行为型模式,其意图是给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。中介者模式(Mediator Pattern):把各个组件(对象)之间的复杂交互通讯通过其中的一个“中介者”来处理。提供一种松耦合的方式,解决对个对象之间复杂的交换问题。在这种模式中,只有一个类彻底清楚其他类的方法,当类发生变化时,他们会通知中介者,在由中介者将改变通知
16、其他相关的类(对象/组件)。 (用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。)(没有的)调停者模式(Mediator):调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显依赖,从而使它们可以松耦合。调停者模式将多对多的相互作用转化为一对多的相互作用。职责链模式(Chain of Responsibility):请求在职责链上传递,直到链上的某一个对象决定处理此请求,客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的情况下动态地重新组织链和分配责任。备忘录模式(Memento):
17、备忘录对象是一个用来存储另外一个对象内部状态的快照的对象,备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态存储起来,从而可以在将来合适的时候把这个对象还原到存储前的状态。策略模式(Strategy):策略模式针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。(属于对象行为型设计模式)访问者模式(Visitor):访问者模式的目的是封装一些施加于某种数据结构元素之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。状态模式(State):状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类,
18、状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。模板模式和策略模式的应用情景类似,但实现方式不同,前者使用继承,后者使用委托。模板模式的缺点是把具体实现和通用算法紧密地耦合起来,使得具体实现只能被一个通用算法操纵,而策略模式是委托的经典用法,策略模式消除了通用算法和具体实现的耦合,使得具体实现可以被多个通用算法操纵,策略模式也增加了类层次,比模板模式复杂。4、 为什么要使用设计模式?使用设计模式有哪些好处?答:好处:指在软件设计和开发过程中,不断总结出来的,反应了某一类设计问题的解决方案模式是一种指导,在一个良好的指导下,有助于你完成任务,有助于你作出一个优良的设计方案,达
19、到事半功倍的效果。而且会得到解决问题的最佳办法,设计模式使人们可以更加简单方便地复用成功的设计和体系结构,设计模式帮助你从别人的成功经验而不是你自己的失败那里学到更多东西。设计模式提供了一种共享经验的方式,可以使团体受益和避免不断的重复发明5、 比较抽象工厂模式和工厂方法模式相似性和差异性。什么情况下使用抽象工厂模式?什么情形下使用工厂方法模式?答:简单工厂模式,工厂方法模式和抽象工厂模式都是属于创建型设计模式,这三种创建型模式都不需要知道具体类。我们掌握一种思想,就是在创建一个对象时,需要把容易发生变化的地方给封装起来,来控制变化(哪里变化,封装哪里),以适应客户的变动,项目的扩展。用这三种
20、设计模式都可以实现,那究竟这三种设计模式有什么异同呢?下面为比较:简单工厂模式:专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。它又称为静态工厂方法模式。它的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。在这个模式中,工厂类是整个模式的关键所在。它包含必要的判断逻辑,能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构的优
21、化。工厂方法模式:工厂方法是粒度很小的设计模式,因为模式的表现只是一个抽象的方法。提前定义用于创建对象的接口,让子类决定实例化具体的某一个类,即在工厂和产品中间增加接口,工厂不再负责产品的创建,由接口针对不同条件返回具体的类实例,由具体类实例去实现。工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现开闭 原则,实现了可扩展。其次实现更复杂的层次结构,可以应用于产品结果复杂的场合。工厂方法模式是对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不在负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂
22、类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。 抽象工厂模式:抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。它有多个抽象产品类,每个抽象产品类可以派生出多个具体产品类,一个抽象工厂类,可以派生出多个具体工厂类,每个具体工厂类可以创建多个具体产品类的实例。每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构;而抽象工厂
23、模式针对的是多个产品等级结果。相似性:都是保留不变的部分提取出来,将可变的部分抽象成接口,以达到最大程度的复用,实现面向对象的开放关闭原则。区别:工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。 工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。抽象工厂适用情况:1、一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。 2、 这个系统有多于一个的产品族,而系统只消费其中某一产品族。 3、 同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。 4、系统提供一个产品类的库,所有的产品以同样的接
24、口出现,从而使客户端不依赖于实现。工厂方法适用情况:1.当一个类不知道它所必须创建的对象的类的时候。 2.当一个类希望由它的子类来指定它所创建的对象的时候。 3.当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。6、 简述原型模式中浅层克隆和深度克隆的区别?分别给出代码说明。答:浅拷贝(影子克隆):只复制对象的基本类型,对象类型,仍属于原来的引用.深拷贝(深度克隆):不紧复制对象的基本类,同时也复制原对象中的对象.就是说完全是新对象产生的.深拷贝与浅拷贝不同的是对于引用的处理,深拷贝将会在新对象中创建一个新的和原是对象中对应字段相同(内容
25、相同)的字段,也就是说这个引用和原是对象的引用是不同的,我们在改变新对象中的这个字段的时候是不会影响到原始对象中对应字段的内容。所以对于原型模式也有不同的两种处理方法:对象的浅拷贝和深拷贝。7、 模板方法和普通的实现类继承抽象类方式有何区别?答:摸板方法(Template Method)模式是一种非常简单而又经常使用的设计模式.先创建一个父类,把其中的一个或多个方法留给子类去实现,这实际上就是在使用摸板模式.所谓的摸板模式可以这样来理解:在一个类中定义一个算法,但将此算法的某些细节留到子类中去实现.换句话说,基类是一个抽象类,那么你就是在使用一种简单形式的摸板模式. 更近一步可以这样来理解:准
26、备一个抽象类,将部分逻辑以具体方法的形式实现,然后申明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方法实现这些抽象方法,从而对剩余的逻辑有不同的实现.模式意图:将一个类的基本部分抽取出来放到一个基类中,这样它就不必重复出现在几个派生类里.模式结构与参与者:抽象摸板角色:1. 定义了一个或多个抽象操作,以便让子类实现.2. 定义并实现了一个摸板方法.具体摸板角色:1. 实现父类所定义的一个或多个抽象方法.2. 每一个抽象摸板角色都可以有任意多个具体摸板角色与之对应.3. 每一个具体摸板角色都可以给出这些抽象方法的不同实现. 模式中的方法种类1. 抽象模板角色里提供完整的方法,它完
27、成了所有派生类都要用到的一些基本功能.2. 抽象模板角色里只提供空方法,把功能全部留给派生类去实现.3. 抽象模板角色里只包含某些操作的默认实现,派生类里可以重新定义这些方法的实现.4. 抽象模板角色里模板方法,他是一个调用抽象方法,钩子方法以及具体方法的各种组合.1)模板方法模式是一种类的行为型模式,在它的结构图中只有类之间的继承关系,没有对象关联关系。2)板方法模式是基于继承的代码复用基本技术,模板方法模式的结构和用法也是面向对象设计的核心之一。在模板方法模式中,可以将相同的代码放在父类中,而将不同的方法实现放在不同的子类中。3)在模板方法模式中,我们需要准备一个抽象类,将部分逻辑以具体方
28、法以及具体构造函数的形式实现,然后声明一些抽象方法来让子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现,这就是模板方法模式的用意。模板方法模式体现了面向对象的诸多重要思想,是一种使用频率较高的模式。8、 是比较和分析适配器模式和桥接模式之间的共性和差异性。答:适配器模式和桥接模式都是间接引用对象,因此可以使系统更灵活,在实现上都涉及从自身以外的一个接口向被引用的对象发出请求。两种模式的区别在于使用场合的不同,适配器模式主要解决两个已经有接口间的匹配问题,这种情况下被适配的接口的实现往往是一个黑匣子。我们不想,也不能修改这个接口及其实现。同时也不可能控
29、制其演化,只要相关的对象能与系统定义的接口协同工作即可。适配器模式经常被用在与第三方产品的功能集成上,采用该模式适应新类型的增加的方式是开发针对这个类型的适配器,桥接模式则不同,参与桥接的接口是稳定的,用户可以扩展和修改桥接中的类,但是不能改变接口。桥接模式通过接口继承实现或者类继承实现功能扩展。按照GOF的说法,桥接模式和适配器模式用于设计的不同阶段,桥接模式用于设计的前期,即在设计类时将类规划为逻辑和实现两个大类,是他们可以分别精心演化;而适配器模式用于设计完成之后,当发现设计完成的类无法协同工作时,可以采用适配器模式。然而很多情况下在设计初期就要考虑适配器模式的使用,如涉及到大量第三方应
30、用接口的情况。9、 请用组合模式实现学校人事管理模式。答:public class Form1 : System.Windows.Forms.Form private System.Windows.Forms.Label lbSalary;private System.ComponentModel.Container components = null;AbstractEmployee prez, marketVP, salesMgr;TreeNode rootNode;AbstractEmployee advMgr, emp, prodVP, prodMgr, shipMgr;private
31、 System.Windows.Forms.TreeView EmpTree;private Random rand;private void init() rand = new Random ();buildEmployeeList();buildTree();private void buildEmployeeList() prez = new Boss(CEO, 200000);marketVP = new Boss(Marketing VP, 100000);prez.add(marketVP);salesMgr = new Boss(Sales Mgr, 50000);advMgr
32、= new Boss(Advt Mgr, 50000);marketVP.add(salesMgr);marketVP.add(advMgr);prodVP = new Boss(Production VP, 100000);prez.add(prodVP);advMgr.add(Secy, 20000);for (int i = 1; i=5; i+)salesMgr.add(Sales + i.ToString(), rand_sal(30000);prodMgr = new Boss(Prod Mgr, 40000);shipMgr = new Boss(Ship Mgr, 35000)
33、;prodVP.add(prodMgr);prodVP.add(shipMgr);for (int i = 1; i=3; i+)shipMgr.add(Ship + i.ToString(), rand_sal(25000);for (int i = 1; i=4; i+)prodMgr.add(Manuf + i.ToString(), rand_sal(20000);private void buildTree() EmpNode nod;nod = new EmpNode(prez);rootNode = nod;EmpTree.Nodes.Add(nod);addNodes(nod,
34、 prez);private void getNodeSum(EmpNode node) AbstractEmployee emp;float sum; emp = node.getEmployee(); sum = emp.getSalaries(); lbSalary.Text = sum.ToString ();private void addNodes(EmpNode nod, AbstractEmployee emp) AbstractEmployee newEmp; EmpNode newNode; IEnumerator empEnum; empEnum = emp.getSub
35、ordinates(); while (empEnum.MoveNext() newEmp = (AbstractEmployee)empEnum.Current; newNode = new EmpNode(newEmp); nod.Nodes.Add(newNode);addNodes(newNode, newEmp);private float rand_sal(float sal) float rnum = rand.Next ();rnum = rnum / Int32.MaxValue;return rnum * sal / 5 + sal;public Form1() Initi
36、alizeComponent();init();protected override void Dispose( bool disposing ) if( disposing ) if (components != null) components.Dispose();base.Dispose( disposing );private void InitializeComponent() STAThreadstatic void Main() Application.Run(new Form1();private void EmpTree_AfterSelect(object sender,
37、TreeViewEventArgs e) EmpNode node;node = (EmpNode)EmpTree.SelectedNode;getNodeSum(node);public class Boss:Employeepublic Boss(string name, float salary):base(name,salary) public Boss(AbstractEmployee emp):base(emp.getName() , emp.getSalary() public override void add(string nm, float salary) Abstract
38、Employee emp = new Employee(nm,salary);subordinates.Add (emp);public override void add(AbstractEmployee emp)subordinates.Add(emp)public override AbstractEmployee getChild() bool found;AbstractEmployee tEmp = null;IEnumerator esub ; if (getName().Equals (getName() return this; else found = false; esu
39、b = subordinates.GetEnumerator (); while (! found & esub.MoveNext() tEmp = (AbstractEmployee)esub.Current; found = (tEmp.getName().Equals(name); if (! found) if (! tEmp.isLeaf() tEmp = tEmp.getChild();found = (tEmp.getName().Equals(name); if (found) return tEmp;else return new Employee(New person, 0
40、);public class Employee :AbstractEmployee protected float salary;protected string name;protected ArrayList subordinates;public Employee(string nm, float salry) subordinates = new ArrayList();name = nm;salary = salry;public float getSalary() return salary;public string getName() return name;public bo
41、ol isLeaf() return subordinates.Count = 0;public virtual void add(string nm, float salary) throw new Exception(No subordinates in base employee class);public virtual void add(AbstractEmployee emp) throw new Exception(No subordinates in base employee class);public IEnumerator getSubordinates() return
42、 subordinates.GetEnumerator ();public virtual AbstractEmployee getChild() return null;public float getSalaries() float sum;AbstractEmployee esub;sum = getSalary();IEnumerator enumSub = subordinates.GetEnumerator() ;while (enumSub.MoveNext() esub = (AbstractEmployee)enumSub.Current;sum += esub.getSal
43、aries();return sum;public interface AbstractEmployee float getSalary();string getName();bool isLeaf();void add(string nm, float salary);void add(AbstractEmployee emp);IEnumerator getSubordinates();AbstractEmployee getChild();float getSalaries();public class EmpNode:TreeNode private AbstractEmployee
44、emp;public EmpNode(AbstractEmployee aemp ):base(aemp.getName () emp = aemp;public AbstractEmployee getEmployee() return emp;10、 综合应用装饰模式、命令模式和状态模式实现工具条命令按钮鼠标进入时高亮显示状态以及鼠标单击按钮后呈现凹陷状态,表明当前按钮为选中状态。答:Decorator类namespace CoolDecpublic interface Decorator void mouseDown(object sender, EventArgs e); void paint(object sender, PaintEventArgs e); Form1窗口names