漫谈Visual C#的组件设计方法

visual|设计

  Properties

  在C#中为类预定义属性是件再简单不过的事,见程序1。

  程序1

using System;
namespace PropertiesDemo
{
 public class MyData
 {
  ...............
 }
 public class Class1
 {
  private MyData _data;
  public MyData Data
  {
   get { return _data; }
  }
  public Class1()
  {
   _data = new MyData();
  }
 }
}
  这是相当常见的属性预定义方式,同时也是个可正常运行的程序,不过其中隐含着一个设计上的问题,那就是创建MyData对象的时机。按照程序2-1的手法,当Class1对象被创建之初,其内的_data对象也随着被创建起来,这造成了Class1对象于创建初期就付出了一个MyData对象的内存成本,这对简单的类来说或如牛毛,但倘若Class1对象中拥有一群这类属性呢?为了解决这类问题,.NET Framework中大量使用Lazy-Allocate(缓分配)技术,见程序2。

  程序2 Lazy-Allocate范例

public class Class1
{
 private MyData _data;
 public MyData Data
 {
  get
  {
   if(_data == null)
    data = new MyData();
   return _data;
  }
 }
 public Class1() { }
}
  Lazy-Allocate的设计概念很简单,就是未使用前不预付成本。相对于程序2-1所使用的Pre-Allocate(预分配)概念,程序2-2采取以时间换取空间的策略,付出存取判断式的代价来减轻空间浪费的情况。当然,Pre-Allocate也不是一无是处,不须预判断的快速存取特色适用于用户必然会存取的属性,但在一些特定的属性上,例如ASP.NET中常见的Style属性就不适合使用Pre-Allocate技巧,因为用户不一定会使用该属性,于此情况下,Lazy-Allocate模式说可以让对象省下一些内存成本。

  Event

  事件处理是组件设计中相当重要的一环,在C#中事件与delegate是紧密相关的,程序3是一个简单的事件范例。

  程序3 简单的事件范例

using System;
namespace EventDemo
{
 public delegate void ProcessHandler(object sender);
 public class Class1
 {
  private event ProcessHandler _processHandler = null;
  public event ProcessHandler ProcessStart
  {
   add
   {
    _processHandler += value;
   }
   remove
   {
    _processHandler -= value;
   }
  }
  public void Process()
  {
   _processHandler(this);
   for(int i = 0; i < 10; i++)
    i = i+1;
  }
  public Class1()
  {}
 }
}
  C#之中delegate扮演着函数指针的角色,用户可以将某个函数加入一个delegate之中,而一个delegate允许用户加入一个以上的函数,当调用此delegate时就等同于调用其内所含的所有函数。不过程序2-3的设计手法潜藏着一个问题,就是当事件数众多时,对象就必须付出相应数量的delegate变量,如程序4所示。

  程序4 传统事件设计

private event ProcessHandler _processStart = null;
private event ProcessHandler _processEnd = null;
private event ProcessHandler _processStep = null;

  不管用户是否用到了这些事件,当对象被创建起来时就得付出这些成本,这在窗口应用程序上更显得可怕,因为Windows Message(窗口消息)的数量以千为单位,假如一个简单的窗口程序就必须付出相对于Windows Message数量的变量成本,这样一来对象岂不成了庞然大物了。针对这个问题,.NET Framework采取了与Lazy-Allocate类似的方式来处理,见程序5。

  程序5 新事件设计模式

public class Class1
{
 private Hashtable _eventList = new Hashtable();
 private static object _processStart = new object();
 private static object _processEnd = new object();
 public event ProcessHandler ProcessStart
 {
  add
  {
   _eventList.Add(_processStart,value);
  }
  remove
  {
   _eventList.Remove(_processStart);
  }
 }
 public event ProcessHandler ProcessEnd
 {
  add
  {
   _eventList.Add(_processEnd,value);
  }
  remove
  {
   _eventList.Remove(_processEnd);
  }
 }
 public void Process()
 {
  ProcessHandler start = (ProcessHandler)_eventList[_processStart];
  ProcessHandler end = (ProcessHandler)_eventList[_processEnd];
  if(start != null) start(this);
   for(int i = 0; i < 10; i++)
    i = i+1;
    if(end != null)
     end(this);
 }
  程序中声明了一个Hashtable类型的对象:_eventList,每一个Class1类的实体都拥有这个对象,另外还声明了两个object类型的对象:_processStart、_processEnd,注意!这两个对象是static(静态)类型,也就是说,不管有多少个对象实体,都只须花费两个object的空间。那这与2-4的范例做法有何不同呢?答案是对象所占的内存大小不同,当用户创建一个对象实体之后,此对象占用了一个Hashtable对象的内存空间,在用户设定了ProcessStart事件时,此对象随之占用了一个Hashtable元素的内存空间,若用户未设定事件,那么此元素的内存空间就不会被占用,相较于2-4范例的预付行为,此方式可以省下不必要付出的内存成本。再详细点说,假设Class1拥有1000个事件,那么程序2-4的做法在对象创建初期就会占用1000个event变量的内存空间,而程序2-5则要付出一个Hashtable对象及1000个static变量的代价,当用户创建了第二个对象时,程序2-4要再次占用了1000个event变量的代价,但程序5只须占用一个Hashtable对象的代价,优劣立见不是吗?很幸运,这种设计概念在.NET Framework中已提供了基础建设,设计人员只要套用即可,见程序6。

  程序6 .NET Framework内建的事件支持

public class Component1:Component
{
 private static object _processStart = new object();
 public event EventHandler ProcessStart
 {
  add
  {
   Events.AddHandler(_processStart,value);
  }
  remove
  {
   Events.RemoveHandler(_processStart,value);
  }
 }
 public void Process()
 {
  EventHandler handler = (EventHandler)Events[_processStart];
  if(handler != null)
   handler(this,null);
 }
}
  只要继承自Component类或其子类就可使用这种方式来处理事件。

  Static Helper Object

  C#是个纯OOP的语言,这代表着它不允许设计人员声明全局性的函数或是变量,它提倡以静态函数与静态变量来取代原本须要使用全局性函数及变量的地方,由于静态函数与静态变量都要声明于类内,这个限制形成群集的效应,同时引出了另一种类型的运用:Static Helper Object,见程序7。

  程序7 Static Helper Object范例

public sealed class DomainHelper
{
 public static string GetCurrentDomainDir()
 {
  return AppDomain.CurrentDomain.BaseDirectory;
 }
 private DomainHelper()
 {}
}
............
MessageBox.Show(DomainHelper.GetCurrentDomainDir());
  DomainHelper是一个不允许继承且具备私有构造函数的类,这代表着设计人员不可能创建或是继承此类,DomainHelper提供了GetCurrentDomainDir静态函数,用来返回目前Application Domain所在的路径,这比起原来调用AppDomain. GetCurrentDomain. BaseDirectory函数来取得同样结果的方式简短了许多。Helper Object的中心概念就是将常用的辅助型函数包装成静态函数,设计人员就无须一再重复地撰写这些程序代码,组件设计技术与Helper Object息息相关,读者们会在后面的章节中看到更多这类型的例子。

时间: 2025-01-06 23:52:09

漫谈Visual C#的组件设计方法的相关文章

Asp.net组件设计浅论

asp.net|设计 一.什么是组件? 查看MSDN,微软是这样给组件定义的:在 .NET Framework 中,组件是指实现 System.ComponentModel.IComponent 接口的一个类,或从实现 IComponent 的类中直接或间接派生的类.这是从纯语言(技术)角度下的定义,通俗的讲,组件是"可独立运作的软件单元",这里强调独立运作,也就代表着组件必须拥有低耦合性.高重用性等特点.微软将软件划分为两部分:其一是Component,意指具备特定功能.可独立运作.

Web App动效设计原则 Web App的设计方法

文章描述:Mobile Web App的设计方法 [编者按]本文作者:邓腾(@千年牛皮糖),百度无线交互设计师 .在本文中,作者将给大家谈谈Mobile Web App的设计方法,内容包括:Web App定义.Web App的特点.发展现状及设计等等.希望对大家有所帮助. Native App与Web App的争论从未停息过,尽管很多人在批判Web App的各种不是,但也阻止不了各种各样的Web App如雨后春笋般出现,尤其是伴随智能手机的普及而受到重视的Mobile Web App.这是一种在

一种全新的软件界面设计方法(摘)

设计 关键字:COM MySpy IE SetUIHanlder IcustomDoc IDocHostUIHandler GetExternal 前言 作者在解决各种问题的时候喜欢首先使用C++ Builder来尝试,这篇文章也是这样,但这并不影响其他开发工具的使用者阅读,因为这都是微软的开发技术,选择什么工具并不重要,我们理解了他的原理可以使用任何工具实现同样的功能. 正文 使用过VC.Net的朋友可能知道,在VC.Net中全新提供了一种基于Web的界面设计方法,不过可能真正用到的人很少,至

COM组件设计与应用(六)——用ATL写第一个组件(vc.net)

一.前言 1.与 <COM 组件设计与应用(五)>的内容基本一致.但本回讲解的是在 vc.net 2003 下的使用方法,即使你不再使用vc6.0,也请和上一回的内容,参照比对. 2.这第一个组件,除了所有 COM 组件必须的 IUnknown 接口外,我们再实现一个自己定义的接口 IFun,它有两个函数: Add()完成两个数值的加法,Cat()完成两个字符串的连接. 3.下面......好好听讲! 开始了:-) 二.建立 ATL 工程 步骤2.1:建立一个解决方案. 步骤2.2:在 该解决

COM组件设计与应用(一)起源及复合文件

一.前言 公元一九九五年某个夜黑风高的晚上,我的一位老师跟我说:"小杨呀,以后写程序就和搭积木一样啦.你赶快学习一些OLE的技术吧......",当时我心里就寻思 :"开什么玩笑?搭积木方式写程序?再过100年吧......",但作为一名听话的好学生,我开始在书店里"踅摸"(注1)有关OLE的书籍(注2).功夫不负有心人,终于买到了我的第一本COM书<OLE2 高级编程技术>,这本800多页的大布头花费了我1/5的月工资呀......

AOP@Work: 用Contract4J进行组件设计-用契约式设计和AspectJ改进软件

简介:契约式设计(Design by Contract)是切实可行的技术,可以阐明组 件 设计的细节.为客户记录正确的组件用法,并用编程的方式测试组件使用的顺应 性(compliance).在 AOP@Work 的最后一篇中,Dean Wampler 介绍 了 Contract4J,这是契约式设计的工具,它用 Java 5 标注 (annotation)指定合约,并在运行时用 AspectJ 方面计算合约.在成为 AOP 工具包中新增的一个举足轻重的工具的同时,Contract4J 迎合了面向方

将存储过程封装为EJB组件的方法

集成 Web 应用服务器和数据库管理 (DBMS) 技术是很多新型商业应用的常见需求.在本文中,我们将讨论该集成的一个方面:如何在会话 Enterprise JavaBeans (EJB) 组件中设计与开发封装或调用现有 DBMS 存储过程的方法.您应该熟悉 EJB 技术.结构化查询语言 (SQL) 和 Java 数据库连接 (JDBC) 的基本知识,以便充分理解本文. 如果您正致力于需要访问或修改在 DMBS 中数据的 Web 应用程序开发,那么可能已经在向基于 EJB 的设计转移.您可能会发

通用社区登陆组件技术分享(开源)中篇:OAuth 登陆组件流程及组件集成方法

上节内容:通用社区登陆组件技术分享(开源)上篇:OAuth 授权登陆介绍   本节包括以下内容: 1:第三方社区账号登陆的授权流程 2:OAuth2 组件的下载及web.config配置 3:OAuth2 组件的5行代码编写流程 4 :总结与下节内容预告     一: 第三方社区账号登陆的授权流程 1:首先从这里开始:用户进入登陆界面   2:用户点击用新浪微博或QQ登陆,系统跳到第三方授权页面,(QQ示例授权界面) 3:确定授权后,第三方跳转返回你的回调页(在应用里设置),通常仍是系统登陆页面

平安科技实战经验:分布式存储元数据设计方法

我们都知道云计算和分布式应用的很重要的一部分内容就是分布式数据存储,而分布式存储元数据的设计是数据存储中重要的环节. 本文来自中生代技术群(FreshmanTechnology)第一期,来自平安科技存储平台负责人王刚分享的<分布式存储元数据设计方法分析>,王刚具有10年软件研发管理经验,长期从事通用基础平台开发,近期接触云计算领域,主要进行存储虚拟化研究和实践.  下为正文: 提起平安,大家首先想到的是"保险",确实平安是从保险起家的一家综合金融服务集团.提起平安科技,估计