类继承composite 传递什么参数

对象容器的问题
在面向对象系统中,我们常会遇到一类具有“容器”特征的对象——即它们在充当对象的同时,又是其他对象的容器。
如果我们要对这样的对象容器进行处理:
上面是客户代码,客户代码里面必须要知道对象的结构,有可能还要使用递归的方法来处理这个对象,这样写耦合性就比较高。客户代码如果能只和IBox发生依赖就很好了,但是现在它还和ContainerBox和SingleBox发生了依赖,这样内部实现的细节就暴露给了外界,并且和外界产生了依赖关系。
动机(Motivation)
上述描述的问题根源在于:客户代码过多地依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引起客户代码的频繁变化,带来了代码的维护性、扩展性等弊端。
如何将“客户代码与复杂的对象容器结构”解耦?让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?
意图(Intent)
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
——《设计模式》GoF
例说Composite应用
以前面的例子为例
改进的方案
期望的客户代码:
接口和SingleBox代码都不变
ContainerBox代码变化
这样做ContainerBox里面的Process方法就不用判断是否是ContainerBox还是SingleBox,因为它们执行的方法名字都叫做Process。而且客户代码也只用调用box的Process方法即可。
但是这里还有一个问题,客户代码访问不了ContainerBox的Add和Remove方法,因为IBox接口里没有定义。
为了解决这个问题,我们可以选择在IBox接口里添加两个方法Add和Remove,然后SingleBox的Add和Remove方法什么都不做或者抛出异常。
但这样的处理方法也和理想的方法有点差距,因为IBox这个类并不符合我们类的单一职责原则,它有SingleBox和ContainerBox二者的职责,因此SingleBox对于Add和Remove也比较不好处理。但是总的来说,我们还是完成了客户代码的解耦工作。
我们看看整个代码的结构,ContainerBox里面包含了很多IBox,这些IBox有的是ContainerBox,有的也是SingleBox,因此它很像一个树形的结构。
结构(Structure)
Component抽象类或者接口对应之前例子中的IBox,Leaf对应SingleBox,Composite对应ContainerBox。客户代码只依赖于Component抽象类或者结构,这正是我们期望的目的。
Composite模式的几个要点
Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致地处理对象和对象容器,无需关心处理的是单个的对象,还是组合的对象容器。
将“客户代码与复杂的对象容器结构”解耦是Composite模式的核心思想,解耦之后,客户代码将与纯粹的抽象接口——而非对象容器的复杂内部实现结构——发生依赖关系,从而更能“应对变化”。
Composite模式中,是将“Add和Remove等和对象容器相关的方法”定义在“表示抽象对象的Component类”中,还是将其定义在“表示对象容器的Composite类”中,是一个关乎“透明性”和“安全性”的两难问题,需要仔细权衡。这里有可能违背面向对象的“单一职责原则”,但是对于这种特殊结构,这又是必须付出的代价。ASP.Net控件的实现在这方面为我们提供了一个很好的示范。
Composite模式在具体实现中,可以让父对象中的子对象反向追朔;如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率。
.NET框架中的Composite应用
ASP.Net中的Panel对象就是一个Composite对象,而Button对象就是Leaf对象。Button和Panel都继承自System.Web.UI.Control类。
它实际上是在Panel里面加了一个Controls属性,然后Controls属性是一个集合属性,它有Add和Remove方法。这样我们的IBox也可以改为:
在ASP.Net中就是这样,每一个控件都有Controls属性,也就是说每个控件都是一种容器控件(除了LiteralControl)。
这种方式把我们对安全性的担忧,统统放到容器(即ASP.Net中的Controls,以及例子中的Boxes)中去处理。
阅读(...) 评论()详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析]
SpringMVC是目前主流的Web MVC框架之一。&
SpringMVC中Controller的方法参数可以是Integer,Double,自定义对象,ServletRequest,ServletResponse,ModelAndView等等,非常灵活。本文将分析SpringMVC是如何对这些参数进行处理的,使读者能够处理自定义的一些参数。
本文使用的demo基于maven。我们先来看一看对应的现象。&
@Controller
@RequestMapping(value = &/test&)
public class TestController {
& @RequestMapping(&/testRb&)
& @ResponseBody
& public Employee testRb(@RequestBody Employee e) {
& @RequestMapping(&/testCustomObj&)
& @ResponseBody
& public Employee testCustomObj(Employee e) {
& @RequestMapping(&/testCustomObjWithRp&)
& @ResponseBody
& public Employee testCustomObjWithRp(@RequestParam Employee e) {
& @RequestMapping(&/testDate&)
& @ResponseBody
& public Date testDate(Date date) {
首先这是一个Controller,有4个方法。他们对应的参数分别是带有@RequestBody的自定义对象、自定义对象、带有@RequestParam的自定义对象、日期对象。
接下来我们一个一个方法进行访问看对应的现象是如何的。
首先第一个testRb:
第二个testCustomObj:
第三个testCustomObjWithRp:
第四个testDate:
为何返回的Employee对象会被自动解析为xml,请看楼主的另一篇博客:戳我
为何Employee参数会被解析,带有@RequestParam的Employee参数不会被解析,甚至报错?
为何日期类型不能被解析?
SpringMVC到底是如何处理这些方法的参数的?
@RequestBody、@RequestParam这两个注解有什么区别?
带着这几个问题。我们开始进行分析。
本文所分析的源码是Spring版本4.0.2
在分析源码之前,首先让我们来看下SpringMVC中两个重要的接口。
两个接口分别对应请求方法参数的处理、响应返回值的处理,分别是HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler,这两个接口都是Spring3.1版本之后加入的。
SpringMVC处理请求大致是这样的:
首先被DispatcherServlet截获,DispatcherServlet通过handlerMapping获得HandlerExecutionChain,然后获得HandlerAdapter。
HandlerAdapter在内部对于每个请求,都会实例化一个ServletInvocableHandlerMethod进行处理,ServletInvocableHandlerMethod在进行处理的时候,会分两部分别对请求跟响应进行处理。
之后HandlerAdapter得到ModelAndView,然后做相应的处理。
本文将重点介绍ServletInvocableHandlerMethod对请求以及响应的处理。
1. 处理请求的时候,会根据ServletInvocableHandlerMethod的属性argumentResolvers(这个属性是它的父类InvocableHandlerMethod中定义的)进行处理,其中argumentResolvers属性是一个HandlerMethodArgumentResolverComposite类(这里使用了组合模式的一种变形),这个类是实现了HandlerMethodArgumentResolver接口的类,里面有各种实现了HandlerMethodArgumentResolver的List集合。
2. 处理响应的时候,会根据ServletInvocableHandlerMethod的属性returnValueHandlers(自身属性)进行处理,returnValueHandlers属性是一个HandlerMethodReturnValueHandlerComposite类(这里使用了组合模式的一种变形),这个类是实现了HandlerMethodReturnValueHandler接口的类,里面有各种实现了HandlerMethodReturnValueHandler的List集合。
ServletInvocableHandlerMethod的returnValueHandlers和argumentResolvers这两个属性都是在ServletInvocableHandlerMethod进行实例化的时候被赋值的(使用RequestMappingHandlerAdapter的属性进行赋值)。
RequestMappingHandlerAdapter的argumentResolvers和returnValueHandlers这两个属性是在RequestMappingHandlerAdapter进行实例化的时候被Spring容器注入的。
其中默认的ArgumentResolvers:
默认的returnValueHandlers:
我们在json、xml自动转换那篇文章中已经了解,使用@ResponseBody注解的话最终返回值会被RequestResponseBodyMethodProcessor这个HandlerMethodReturnValueHandler实现类处理。
我们通过源码发现,RequestResponseBodyMethodProcessor这个类其实同时实现了HandlerMethodReturnValueHandler和HandlerMethodArgumentResolver这两个接口。
RequestResponseBodyMethodProcessor支持的请求类型是Controller方法参数中带有@RequestBody注解,支持的响应类型是Controller方法带有@ResponseBody注解。&
RequestResponseBodyMethodProcessor响应的具体处理是使用消息转换器。
处理请求的时候使用内部的readWithMessageConverters方法。
然后会执行父类(AbstractMessageConverterMethodArgumentResolver)的readWithMessageConverters方法。
下面来我们来看看常用的HandlerMethodArgumentResolver实现类(本文粗略讲下,有兴趣的读者可自行研究)。
1. RequestParamMethodArgumentResolver
&支持带有@RequestParam注解的参数或带有MultipartFile类型的参数
2. RequestParamMapMethodArgumentResolver
& 支持带有@RequestParam注解的参数 && @RequestParam注解的属性value存在 && 参数类型是实现Map接口的属性
3. PathVariableMethodArgumentResolver
支持带有@PathVariable注解的参数 且如果参数实现了Map接口,@PathVariable注解需带有value属性
4. MatrixVariableMethodArgumentResolver
支持带有@MatrixVariable注解的参数 且如果参数实现了Map接口,@MatrixVariable注解需带有value属性&
5. RequestResponseBodyMethodProcessor
&本文已分析过
6. ServletRequestMethodArgumentResolver
&参数类型是实现或继承或是WebRequest、ServletRequest、MultipartRequest、HttpSession、Principal、Locale、TimeZone、InputStream、Reader、HttpMethod这些类。
(这就是为何我们在Controller中的方法里添加一个HttpServletRequest参数,Spring会为我们自动获得HttpServletRequest对象的原因)
7. ServletResponseMethodArgumentResolver
&参数类型是实现或继承或是ServletResponse、OutputStream、Writer这些类
8. RedirectAttributesMethodArgumentResolver
&参数是实现了RedirectAttributes接口的类
9. HttpEntityMethodProcessor
&参数类型是HttpEntity
从名字我们也看的出来, 以Resolver结尾的是实现了HandlerMethodArgumentResolver接口的类,以Processor结尾的是实现了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler的类。
下面来我们来看看常用的HandlerMethodReturnValueHandler实现类。
1. ModelAndViewMethodReturnValueHandler
返回值类型是ModelAndView或其子类
2. ModelMethodProcessor
返回值类型是Model或其子类
3. ViewMethodReturnValueHandler
返回值类型是View或其子类&
4. HttpHeadersReturnValueHandler
返回值类型是HttpHeaders或其子类 &
5. ModelAttributeMethodProcessor
返回值有@ModelAttribute注解
6. ViewNameMethodReturnValueHandler
返回值是void或String
其余没讲过的读者可自行查看源码。
下面开始解释为何本文开头出现那些现象的原因:
1. 第一个方法testRb以及地址 https://localhost:8888/SpringMVCDemo/test/testRb?name=1&age=3
  这个方法的参数使用了@RequestBody,之前已经分析过,被RequestResponseBodyMethodProcessor进行处理。之后根据http请求头部的contentType然后选择合适的消息转换器进行读取。
  很明显,我们的消息转换器只有默认的那些跟部分json以及xml转换器,且传递的参数name=1&age=3,传递的头部中没有content-type,默认使用了application/octet-stream,因此触发了HttpMediaTypeNotSupportedException异常
  解放方案: 我们将传递数据改成json,同时http请求的Content-Type改成application/json即可。
完美解决。
2. testCustomObj方法以及地址 https://localhost:8888/SpringMVCDemo/test/testCustomObj?name=1&age=3
这个请求会找到ServletModelAttributeMethodProcessor这个resolver。默认的resolver中有两个ServletModelAttributeMethodProcessor,只不过实例化的时候属性annotationNotRequired一个为true,1个为false。这个ServletModelAttributeMethodProcessor处理参数支持@ModelAttribute注解,annotationNotRequired属性为true的话,参数不是简单类型就通过,因此选择了ServletModelAttributeMethodProcessor,最终通过DataBinder实例化Employee对象,并写入对应的属性。
3. testCustomObjWithRp方法以及地址 https://localhost:8888/SpringMVCDemo/test/testCustomObjWithRp?name=1&age=3
这个请求会找到RequestParamMethodArgumentResolver(使用了@RequestParam注解)。RequestParamMethodArgumentResolver在处理参数的时候使用request.getParameter(参数名)即request.getParameter(&e&)得到,很明显我们的参数传的是name=1&age=3。因此得到null,RequestParamMethodArgumentResolver处理missing value会触发MissingServletRequestParameterException异常。 [粗略讲下,有兴趣的读者请自行查看源码]
& & 解决方案:去掉@RequestParam注解,让ServletModelAttributeMethodProcessor来处理。
4. testDate方法以及地址 https://localhost:8888/SpringMVCDemo/test/testDate?date=
这个请求会找到RequestParamMethodArgumentResolver。因为这个方法与第二个方法一样,有两个RequestParamMethodArgumentResolver,属性useDefaultResolution不同。RequestParamMethodArgumentResolver支持简单类型,ServletModelAttributeMethodProcessor是支持非简单类型。最终步骤跟第三个方法一样,我们的参数名是date,于是通过request.getParameter(&date&)找到date字符串(这里参数名如果不是date,那么最终页面是空白的,因为没有@RequestParam注解,参数不是必须的,RequestParamMethodArgumentResolver处理null值返回null)。最后通过DataBinder找到合适的属性编辑器进行类型转换。最终找到java.util.Date对象的构造函数 public Date(String s),由于我们传递的格式不是标准的UTC时间格式,因此最终触发了IllegalArgumentException异常。
& & 解决方案:
& & 1. 传递参数的格式修改成标准的UTC时间格式:https://localhost:8888/SpringMVCDemo/test/testDate?date=Sat, 17 May :00 GMT
& & 2.在Controller中加入自定义属性编辑器。
@InitBinder
public void initBinder(WebDataBinder binder) {
& SimpleDateFormat dateFormat = new SimpleDateFormat(&yyyy-MM-dd&);
& binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
&这个@InitBinder注解在实例化ServletInvocableHandlerMethod的时候被注入到WebDataBinderFactory中的,而WebDataBinderFactory是ServletInvocableHandlerMethod的一个属性。在RequestMappingHandlerAdapter源码的803行getDataBinderFactory就是得到的WebDataBinderFactory。
之后RequestParamMethodArgumentResolver通过WebDataBinderFactory创建的WebDataBinder里的自定义属性编辑器找到合适的属性编辑器(我们自定义的属性编辑器是用CustomDateEditor处理Date对象,而testDate的参数刚好是Date),最终CustomDateEditor把这个String对象转换成Date对象。
编写自定义的HandlerMethodArgumentResolver
通过前面的分析,我们明白了SpringMVC处理Controller中的方法的参数流程。
现在,如果方法中有两个参数,且都是自定义类参数,那该如何处理呢?
@RequestMapping(&/save&)
public ModelAndView saveAll(@FormModel Employee employee, @FormModel Dept dept, ModelAndView view) {
& view.setViewName(&test/success&);
& view.addObject(&employee&, employee);
& view.addObject(&dept&, dept);
我们就来试试吧。
很明显,要处理这个只能自己实现一个实现HandlerMethodArgumentResolver的类。1887人阅读
Design Patterns(24)
23种GOF设计模式一般分为三大类:创建型模式、结构型模式、行为模式。创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建、组合和表示它的那些对象。一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象。创建型模式有两个不断出现的主旋律。第一,它们都将关于该系统使用哪些具体的类的信息封装起来。第二,它们隐藏了这些类的实例是如何被创建和放在一起的。整个系统关于这些对象所知道的是由抽象类所定义的接口。因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以及何时创建这些方面给予了很大的灵活性。它们允许用结构和功能差别很大的“产品”对象配置一个系统。配置可以是静态的(即在编译时指定),也可以是动态的(在运行时)。结构型模式涉及到如何组合类和对象以获得更大的结构。结构型类模式采用继承机制来组合接口或实现。结构型对象模式不是对接口和实现进行组合,而是描述了如何对一些对象进行组合,从而实现新功能的一些方法。因为可以在运行时刻改变对象组合关系,所以对象组合方式具有更大的灵活性,而这种机制用静态类组合是不可能实现的。行为模式涉及到算法和对象间职责的分配。行为模式不仅描述对象或类的模式,还描述它们之间的通信模式。这些模式刻画了在运行时难以跟踪的复杂的控制流。它们将用户的注意力从控制流转移到对象间的联系方式上来。行为类模式使用继承机制在类间分派行为。行为对象模式使用对象复合而不是继承。一些行为对象模式描述了一组对等的对象怎样相互协作以完成其中任一个对象都无法单独完成的任务。创建型模式包括:1、FactoryMethod(工厂方法模式);2、Abstract Factory(抽象工厂模式);3、Singleton(单例模式);4、Builder(建造者模式、生成器模式);5、Prototype(原型模式).结构型模式包括:6、Bridge(桥接模式);7、Adapter(适配器模式);8、Decorator(装饰模式);9、Composite(组合模式);10、Flyweight(享元模式);11、Facade(外观模式);12、Proxy(代理模式).行为模式包括:13、TemplateMethod(模板方法模式);14、Strategy(策略模式);15、State(状态模式);16、Observer(观察者模式);17、Memento(备忘录模式);18、Mediator(中介者模式);19、Command(命令模式);20、Visitor(访问者模式);21、Chain of Responsibility(责任链模式);22、Iterator(迭代器模式);23、Interpreter(解释器模式).Factory Method:定义一个用于创建对象的接口,让子类决定将哪一个类实例化。Factory Method使一个类的实例化延迟到其子类。Abstract Factory:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。Singleton:保证一个类仅有一个实例,并提供一个访问它的全局访问点。Builder:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。Prototype:用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。Bridge:将抽象部分与它的实现部分分离,使它们都可以独立地变化。Adapter:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。Decorator:动态地给一个对象添加一些额外的职责。就扩展功能而言, Decorator模式比生成子类方式更为灵活。Composite:将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得客户对单个对象和复合对象的使用具有一致性。Flyweight:运用共享技术有效地支持大量细粒度的对象。Facade:为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。Proxy:为其他对象提供一个代理以控制对这个对象的访问。Template Method:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。Strategy:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法的变化可独立于使用它的客户。State:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。Observer:定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。Memento:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的状态。Mediator:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。Command:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。Visitor:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。Chain of Responsibility:为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。Iterator:提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。Interpreter:给定一个语言, 定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子。&&&&&&&& Composite:(1)、意图:将对象组合成树形结构以表示“部分--整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。&&&&&&&& (2)、适用性:A、你想表示对象的部分--整体层次结构;B、你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。&&&&&&&& (3)、优缺点:A、定义了包含基本对象和组合对象的类层次结构:基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断的递归下去。客户代码中,任何用到基本对象的地方都可以使用组合对象。B、简化客户代码:客户可以一致地使用组合结构和单个对象。通常用户不知道(也不关心)处理的是一个叶节点还是一个组合组件。这就简化了客户代码,因为在定义组合的那些类中不需要写一些充斥着选择语句的函数。C、使得更容易增加新类型的组件:新定义的Composite或Leaf子类自动地与已有的结构和客户代码一起工作,客户程序不需要因新的Component类而改变。D、使你的设计变得更加一般化:有时你希望一个组合只能有某些特定的组件。使用Composite时,你不能依赖类型系统施加这些约束,而必须在运行时刻进行检查。&&&&&&&& (4)、注意事项:A、显示的父部件引用:保持从子部件到父部件的引用能简化组合结构的遍历和管理。父部件引用可以简化结构的上移和组件的删除,同时父部件引用也支持Chain of Responsibility。B、共享组件:共享组件是很有用的,比如它可以减少对存贮的需求。但是当一个组件只有一个父部件时,很难共享组件。C、最大化Component接口:Composite模式的目的之一是使得用户不知道他们正在使用的具体的Leaf和Composite类。为了达到这一目的,Composite类应为Leaf和Composite类尽可能多定义一些公共操作。Composite类通常为这些操作提供缺省的实现,而Leaf和Composite子类可以对它们进行重定义。D、声明管理子部件的操作。E、Component是否应该实现一个Component列表:你可能希望在Component类中将子节点集合定义为一个实例变量,而这个Component类中也声明了一些操作对子节点进行访问和管理。但是在基类中存放子类指针,对叶节点来说会导致空间浪费,因为叶节点根本没有子节点。只有当该结构中子类数目相对较少时,才值得使用这种方法。F、子部件排序:如果需要考虑子节点的顺序时,必须仔细地设计对子节点的访问和管理接口,以便管理子节点序列。Iterator模式可以在这方面给予一些指导。G、使用高速缓冲存贮改善性能:如果你需要对组合进行频繁的遍历或查找,Composite类可以缓冲存储对它的子节点进行遍历或查找相关信息。H、应该由谁删除Component:在没有垃圾回收机制的语言中,当一个Composite被销毁时,通常最好由Composite负责删除其子节点。但有一种情况除外,即Leaf对象不会改变,因此可以被共享。I、存贮组件最好用哪一种数据结构:Composite可使用多种数据结构存贮它们的子节点,包括连接列表、树、数组和hash表。数据结构的选择取决于效率。事实上,使用通用数据结构根本没有必要。有时对每个子节点,Composite都有一个变量与之对应,这就要求Composite的每个子类都要实现自己的管理接口。&&&&&&&& (5)、相关模式:A、通常部件----父部件连接用于Responsibilityof Chain模式。B、Decorator模式经常与Composite模式一起使用。当装饰和组合一起使用时,它们通常有一个公共的父类。因此装饰必须支持具有Add、Remove和GetChild操作的Component接口。C、Flyweight让你共享组件,但不再能引用他们的父部件。D、Iterator可用来遍历Composite. E、Visitor将本来应该分布在Composite和Leaf类中的操作和行为局部化。&&&&&&&& Composite模式在实现中有一个问题就是要提供对于子节点(Leaf)的管理策略,可以提供的实现方式有:vector、数组、链表、Hash表等。&&&&&&&& Composite模式通过和Decorator模式有着类似的结构图,但是Composite模式旨在构造类,而Decorator模式重在不生成子类即可给对象添加职责。Decorator模式重在修饰,而Composite模式重在表示。示例代码1:#include &iostream&
#include &string&
#include &vector&
class Component
string m_strN
Component(string strName)
m_strName = strN
virtual void Add(Component* com) = 0;
virtual void Display(int nDepth) = 0;
class Leaf : public Component
Leaf(string strName) : Component(strName) {}
virtual void Add(Component* com)
cout&&&leaf can't add&&&
virtual void Display(int nDepth)
for (int i = 0; i & nD i ++)
strtemp += &-&;
strtemp += m_strN
cout&&strtemp&&
class Composite : public Component
vector&Component*& m_
Composite(string strName) : Component(strName) {}
virtual void Add(Component* com)
m_component.push_back(com);
virtual void Display(int nDepth)
for (int i = 0; i & nD i ++)
strtemp += &-&;
strtemp += m_strN
cout&&strtemp&&
vector&Component*&::iterator p = m_component.begin();
while (p != m_component.end()) {
(*p)-&Display(nDepth + 2);
int main()
Composite* p = new Composite(&小王&);
p-&Add(new Leaf(&小李&));
p-&Add(new Leaf(&小赵&));
Composite* p1 = new Composite(&小小五&);
p1-&Add(new Leaf(&大三&));
p-&Add(p1);
p-&Display(1);
}示例代码2:#include &iostream&
#include &string&
#include &vector&
class Company
protected:
string m_strN
Company(string strName)
m_strName = strN
virtual void Add(Company* c) = 0;
virtual void Display(int nDepth) = 0;
virtual void LineOfDuty() = 0;
class ConcreteCompany : public Company
vector&Company*& m_
ConcreteCompany(string strName) : Company(strName) {}
virtual void Add(Company* c)
m_company.push_back(c);
virtual void Display(int nDepth)
for (int i = 0; i & nD i ++)
strtemp += &-&;
strtemp += m_strN
cout&&strtemp&&
vector&Company*&::iterator p = m_company.begin();
while (p != m_company.end()) {
(*p)-&Display(nDepth + 1);
virtual void LineOfDuty()
vector&Company*&::iterator p = m_company.begin();
while (p != m_company.end()) {
(*p)-&LineOfDuty();
class HrDepartment : public Company
HrDepartment(string strname) : Company(strname) {}
virtual void Display(int nDepth)
for (int i = 0; i & nD i ++)
strtemp += &-&;
strtemp += m_strN
cout&&strtemp&&
virtual void Add(Company* c)
cout&&&error&&&
virtual void LineOfDuty()
cout&&m_strName&&&:招聘人才&&&
int main()
ConcreteCompany* p = new ConcreteCompany(&清华大学&);
p-&Add(new HrDepartment(&清华大学人才部&));
ConcreteCompany* p1 = new ConcreteCompany(&数学系&);;
p1-&Add(new HrDepartment(&数学系人才部&));
ConcreteCompany* p2 = new ConcreteCompany(&物理系&);
p2-&Add(new HrDepartment(&物理系人才部&));
p-&Add(p1);
p-&Add(p2);
p-&Display(1);
p-&LineOfDuty();
--清华大学人才部
---数学系人才部
---物理系人才部
清华大学人才部:招聘人才
数学系人才部:招聘人才
物理系人才部:招聘人才
}示例代码3:Component.h:#ifndef _COMPONENT_H_
#define _COMPONENT_H_
class Component
Component();
virtual ~Component();
virtual void Operation() = 0;
virtual void Add(const Component&);
virtual void Remove(const Component&);
virtual Component* GetChild(int);
protected:
#endif//~_COMPONENT_H_Component.cpp:#include &Component.h&
Component::Component()
Component::~Component()
void Component::Add(const Component&)
Component* Component::GetChild(int index)
void Component::Remove(const Component& com)
Composite.h:#ifndef _COMPOSITE_H_
#define _COMPOSITE_H_
#include &Component.h&
#include &vector&
class Composite : public Component
Composite();
~Composite();
void Operation();
void Add(Component* com);
void Remove(Component* com);
Component* GetChild(int index);
protected:
vector&Component*& comV
#endif//~_COMPOSITE_H_Composite.cpp:#include &Composite.h&
#include &Component.h&
#define NULL 0 //define NULL POINTOR
Composite::Composite()
//vector&Component*&::iterator itend = comVec.begin();
Composite::~Composite()
void Composite::Operation()
vector&Component*&::iterator comIter = comVec.begin();
for (; comIter != comVec.end(); comIter ++)
(*comIter)-&Operation();
void Composite::Add(Component* com)
comVec.push_back(com);
void Composite::Remove(Component* com)
//comVec.erase(&com);
Component* Composite::GetChild(int index)
return comVec[index];
}Leaf.h:#ifndef _LEAF_H_
#define _LEAF_H_
#include &Component.h&
class Leaf : public Component
void Operation();
protected:
#endif //~_LEAF_H_Leaf.cpp:#include &Leaf.h&
#include &iostream&
Leaf::Leaf()
Leaf::~Leaf()
void Leaf::Operation()
cout&&&Leaf Operation ...&&&
}main.cpp:#include &Component.h&
#include &Composite.h&
#include &Leaf.h&
#include &iostream&
int main()
Leaf* l = new Leaf();
l-&Operation();
Composite* com = new Composite();
com-&Add(l);
com-&Operation();
Component* ll = com-&GetChild(0);
ll-&Operation();
Leaf Operation ...
Leaf Operation ...
Leaf Operation ...
}组合模式结构图:参考文献:1、《大话设计模式C++》2、《设计模式精解----GoF23种设计模式解析》3、《设计模式----可复用面向对象软件的基础》
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:3407182次
积分:34200
积分:34200
排名:第149名
原创:506篇
转载:140篇
评论:1879条
(7)(29)(10)(18)(9)(14)(21)(16)(11)(16)(9)(19)(11)(8)(7)(16)(14)(12)(10)(5)(8)(4)(1)(3)(7)(7)(3)(2)(8)(2)(2)(8)(9)(10)(4)(4)(4)(5)(4)(4)(6)(9)(12)(1)(4)(11)(4)(5)(4)(1)(1)(3)(3)(2)(1)(2)(1)(1)(2)(3)(4)(1)(2)(2)(4)(2)(4)(2)(6)(2)(3)(3)(6)(11)(9)(1)(13)(16)(11)(12)(17)(4)(8)(17)(13)(14)(17)(2)(1)(2)

我要回帖

更多关于 c 继承的传递性 的文章

 

随机推荐