来源于WCF的设计模式:可扩展对象模式[上篇]

简介:

我一直很喜欢剖析微软一些产品、框架的底层实现。在我看来,这不但让我们可以更加深入地了解其运作的原理,同时也能提高设计/架构的技能。因为对于这些框架或者产品来说,高质量的设计是它们能够成功的一个最基本的因素。比如说比如ASP.NET,不但能够支持传统的Web Form应用,MVC同样建立在它基础之上。比如说WCF,从其诞生的那一天开始,真个架构体系就从未改变。这些应用在这些产品和框架上的设计其实是最值得我们学习的设计案例。比如说,今天我们介绍的“可扩展对象模式(Extensible Object Pattern)”就来源于WCF。[源代码从这里下载]

一、一个简单的“可扩展对象模式”的实现

为了让这种所谓的“可扩展对象模式”有一个大概的了解,我们先来演示一个简单的例子。现在有一个表示房间的类型Room,它具有几个基本的属性Walls、Windows和Door分别表示房间的墙、窗户和门。现在我们要来创建一个Room对象,即分别创建组成这个Room对象的各个构成元素。按照“大事化小”这个基本的设计原则,我们分别创建相应的Builder来分别为Room构建相应的元素。按照“可扩展对象模式”的原理,Room对象就是一个可扩展对象,而相应的Builder实现了对它的扩展。现在我们将Room这个类型定义在实现了接口IExtensibleObject<Room>的可扩展对象。

   1: public class Room : IExtensibleObject<Room>
   2: {
   3:     public Room()
   4:     {
   5:         this.Extensions = new ExtensionCollection<Room>(this);
   6:     }
   7:     public Door Door { get; set; }
   8:     public IList<Wall> Walls { get; set; }
   9:     public Window Window { get; set; }
  10:     public IExtensionCollection<Room> Extensions { get; private set; }
  11: }
  12: public class Door{}
  13: public class Wall{}
  14: public class Window{}

为Room对象构建门、窗和墙的Builder(DoorBuilder、WindowBuilder和WallBuilder)均实现了相同的接口IExtension<Room>,表明它们都是针对Room的扩展。

   1: public class DoorBuilder : IExtension<Room>
   2: {
   3:     public Door Door { get; private set; }
   4:     public void Attach(Room owner)
   5:     {
   6:         owner.Door = this.Door = new Door();
   7:     }
   8:     public void Detach(Room owner)
   9:     {
  10:         if (this.Door == owner.Door)
  11:         {
  12:             owner.Door = null;
  13:             this.Door = null;
  14:         }
  15:     }
  16: }
  17:  
  18: public class WindowBuilder : IExtension<Room>
  19: {
  20:     public Window Window { get; private set; }
  21:     public void Attach(Room owner)
  22:     {
  23:         owner.Window = this.Window = new Window();
  24:     }
  25:     public void Detach(Room owner)
  26:     {
  27:         if (this.Window == owner.Window)
  28:         {
  29:             owner.Window = null;
  30:             this.Window = null;
  31:         }
  32:     }
  33: }
  34:  
  35: public class WallBuilder : IExtension<Room>
  36: {
  37:     public Wall[] Walls { get; private set;}
  38:     public void Attach(Room owner)
  39:     {
  40:         owner.Walls = this.Walls = new Wall[] { new Wall(), new Wall(), new Wall(), new Wall() };
  41:     }
  42:     public void Detach(Room owner)
  43:     {
  44:         if (null == owner.Walls || null== this.Walls)
  45:         {
  46:             this.Walls = null;
  47:             return;
  48:         }
  49:         Array.ForEach(this.Walls, wall =>
  50:             {
  51:                 if (owner.Walls.Contains(wall))
  52:                 {
  53:                     owner.Walls.Remove(wall);
  54:                 }
  55:             });
  56:         this.Walls = null;
  57:     }
  58: }

现在我们真正创建Room对象的程序写成如下形式:先创建可扩展对象Room,并将用于用于构建相应元素的三个Builder添加到以Extensions属性表示的扩展集合中。经过这个简单的过程,一个完整的Room对象就已经被正常的构建了。这个简单的应用体现和很好的可扩展性:任何针对Room对象的扩展都可以通过相应扩展对象(IExtension<Room>)来实现,如果我们需要,只需要将这些扩展添加到它的Extensions集合中就可以了。

   1: Room room = new Room();
   2: room.Extensions.Add(new DoorBuilder());
   3: room.Extensions.Add(new WindowBuilder());
   4: room.Extensions.Add(new WallBuilder());
   5:  
   6: Debug.Assert(room.Door != null, "Door has not been built!");
   7: Debug.Assert(room.Window != null, "Window has not been built!");
   8: Debug.Assert(room.Walls != null, "Walls have not been built!");

二、IExtensibleObject<T>和IExtension<T>

这个可扩展对象模式涉及到两个基本的接口,即IExtensibleObject<T>和IExtension<T>,前者代表可扩展对象,后者代表对这个可扩展对象的扩展,而这个泛型参数T则代表定义成可扩展对象的类型。我想如果你是第一个接触者两个接口,看到这个介绍你可能会觉得很晕,尤其是“可扩展对象类型T实现接口IExtensibleObject<T>”,不过多想想,应该会很快绕过弯子来的。

IExtensibleObject<T>接口仅仅定义了一个唯一的属性Extensions,而它类型是IExteniosnCollection<T>代表针对可扩展对象类型T的扩展的集合。System.ServiceModel定义了具体的集合类型ExteniosnCollection<T>实现了IExteniosnCollection<T>接口

   1: public interface IExtensibleObject<T> where T: IExtensibleObject<T>
   2: {
   3:     IExtensionCollection<T> Extensions { get; }
   4: }

而所谓的“针对可扩展对象类型T的扩展”就是实现了第二个接口IExtension<T>的对象。该接口具有两个方法Attach和Detach,具体相同的参数owner。当我们将某个扩展对象添加到某个可扩展对象的Extensions集合中的时候,Attach方法会自动被调用,而传入的参数owner就是这个需要被扩展的对象。与此相对,Detach则在当该扩展对象从可扩展对象的Extensions集合中移出的时候被调用。

   1: public interface IExtension<T> where T: IExtensibleObject<T>
   2: {
   3:     void Attach(T owner);
   4:     void Detach(T owner);
   5: }

在前面的例子中,我们将DoorBuilder、WindowBuilder和WallBuilder实现IExtension<Room>接口,将相应的针对门、窗和墙的构建实现在Attach方法中。所以当它们被作为对Room对象的扩展添加到一个具体的Room对象的Extensions集合上的时候,这个Romm对象就分别有了一道门、一扇窗和四面墙。此外,由于被添加的Builder有可能被移除,如果被移除后,先前被创建的门、窗和墙应该也一并移掉,而这些操作被定义在Detach方法中。

三、总结

在这里,我们将围绕着IExtensibleObject<T>和IExtension<T>这两个接口的设计方式说成一种“设计模式”,可能不太妥当。实际上,任何存在扩展可能的类型都可以按照这样的方式来设计。而我们熟悉的一些设计模式都可以按照“可扩展对象”的方式来设计。文中Room采用的涉及模式可以看成是Builder模式。

注:关于“可扩展对象模式”,李会军同学写了一篇很好的文章《技巧:使用可扩展对象模式扩展HttpApplication

来源于WCF的设计模式:可扩展对象模式[上篇]
来源于WCF的设计模式:可扩展对象模式[下篇]


作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
7月前
|
设计模式 网络协议 数据可视化
Java 设计模式之状态模式:让对象的行为随状态优雅变化
状态模式通过封装对象的状态,使行为随状态变化而改变。以订单为例,将待支付、已支付等状态独立成类,消除冗长条件判断,提升代码可维护性与扩展性,适用于状态多、转换复杂的场景。
931 157
|
设计模式 Java 数据库连接
【设计模式】【创建型模式】工厂方法模式(Factory Methods)
一、入门 什么是工厂方法模式? 工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定实例化哪个类。工厂方法模式使类的实例化延迟
332 16
|
12月前
|
设计模式 负载均衡 监控
并发设计模式实战系列(2):领导者/追随者模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第二章领导者/追随者(Leader/Followers)模式,废话不多说直接开始~
338 0
|
12月前
|
设计模式 监控 Java
并发设计模式实战系列(1):半同步/半异步模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第一章半同步/半异步(Half-Sync/Half-Async)模式,废话不多说直接开始~
466 0
|
12月前
|
设计模式 安全 Java
并发设计模式实战系列(12):不变模式(Immutable Object)
🌟 大家好,我是摘星!🌟今天为大家带来的是并发设计模式实战系列,第十二章,废话不多说直接开始~
280 0
|
12月前
|
设计模式 算法 Java
设计模式觉醒系列(04)策略模式|简单工厂模式的升级版
本文介绍了简单工厂模式与策略模式的概念及其融合实践。简单工厂模式用于对象创建,通过隐藏实现细节简化代码;策略模式关注行为封装与切换,支持动态替换算法,增强灵活性。两者结合形成“策略工厂”,既简化对象创建又保持低耦合。文章通过支付案例演示了模式的应用,并强调实际开发中应根据需求选择合适的设计模式,避免生搬硬套。最后推荐了JVM调优、并发编程等技术专题,助力开发者提升技能。
|
设计模式 存储 Java
【再谈设计模式】备忘录模式~对象状态的守护者
备忘录模式属于行为型设计模式。它的主要目的是在不破坏对象封装性的前提下,捕获并外部化一个对象的内部状态,以便之后可以将该对象恢复到这个状态。原发器(Originator):创建一个备忘录,用于记录当前时刻它的内部状态。原发器还可以使用备忘录来恢复其内部状态。备忘录(Memento):存储原发器对象的内部状态。备忘录应该防止原发器以外的其他对象访问其内部状态。负责人(Caretaker):负责保存备忘录,但不能对备忘录的内容进行操作或检查。
454 82
|
设计模式 供应链 安全
【再谈设计模式】中介者模式 - 协调对象间交互的枢纽
中介者模式定义了一个中介对象来封装一组对象之间的交互方式。中介者使得各对象之间不需要显式地相互引用,从而降低了它们之间的耦合度。它通过将对象之间的交互逻辑集中到中介者对象中,使得系统的结构更加清晰,易于维护和扩展。
374 18
【再谈设计模式】中介者模式 - 协调对象间交互的枢纽
|
12月前
|
设计模式 Prometheus 监控
并发设计模式实战系列(20):扇出/扇入模式(Fan-Out/Fan-In)(完结篇)
🌟 大家好,我是摘星!🌟今天为大家带来的是并发设计模式实战系列,第二十章,废话不多说直接开始~
379 0
|
设计模式 Java 关系型数据库
设计模式:工厂方法模式(Factory Method)
工厂方法模式是一种创建型设计模式,通过将对象的创建延迟到子类实现解耦。其核心是抽象工厂声明工厂方法返回抽象产品,具体工厂重写该方法返回具体产品实例。适用于动态扩展产品类型、复杂创建逻辑和框架设计等场景,如日志记录器、数据库连接池等。优点包括符合开闭原则、解耦客户端与具体产品;缺点是可能增加类数量和复杂度。典型应用如Java集合框架、Spring BeanFactory等。