关闭

组件化开发

标签: C#面向对象.net
662人阅读 评论(0) 收藏 举报
分类:

组件化开发概述

软件系统开发面临的困境与突破尝试
  1. 软件代码难以读懂和维护,业务逻辑分散在多个代码模块中
  2. 软件系统面对着的需求不断变化,再次开发一个新的软件成本高
  • 因此,我们应该“重用”,而不是每次都“从头开始”
  • 大量的软件系统中都存在着功能重复的情况,因而开发可重用的软件组件是可行的。


组件(Component):
  • 是指可以用于重用、开发和部署的软件模块。
组件化开发(CBD:Component-based Development)
  • 以可重用的组件为基础“装配出”解决需求软件的过程。

组件实现的功能:
  • 组件的功能是通过其接口(是宏观意义的接口,指向外界提供的功能)来表达;
  • 组件只是黑盒,外界只能通过接口来访问,外界只关系通过接口可以实现的功能,并不关心组件的技术细节;
  • 组件具有独立性和可组合性。

  • 因此,创建可以当“积木”组合的软件组件是组件化开发的核心工作之一。

组件设计的基本原则
  1. 组件设计首先是组件接口的设计,这个组件该干什么事情,每个组件都应有一个明确的职责,只做好一件事,体现为一个明确的组件接口;
  2. 组件的具体实现技术。
  • 组件需按职责进行设计!!
  • 为实现复用而设计
    • 允许围绕该组件的应用自由改变而无需改变组件自身,除非组件自己的功能需求改变,即只会改变其内部的技术实现,而不会改变其对外接口。
  • 仔细考虑组件功能集合的大小
    • 组件的粒度是用于衡量组件所提供的功能集的大小、所封装的代码量多少等与“规模”相关的特性。
    1. 小组件(如一个只允许输入邮编的文本框);
    2. 大组件:一个预先构造的应用软件包(如一个用于生成复杂报表的组件,用于文档处理的office软件包)。
    • 粒度大小与灵活性通常成反比,与易用性成正比!

组件化软件开发的“三板斧”(套路):
  1. 重用已有组件;
  2. 开发部分新组件;
  3. 组合新旧组件搭建出新系统。

组件化软件的开发方式:


组件化开发全过程

实例:两数相加程序:从“天下一统”到“借鸡生蛋”


  • 原始版本

  • 原始需求:输入框接收用户输入,“=”按钮计算结果。
    • “=”按钮事件:
        private void btnAdd_Click(object sender, EventArgs e)
        {
            try
            {
                int num1 = Convert.ToInt32(txtNumber1.Text);
                int num2 = Convert.ToInt32(txtNumber2.Text);
                lblResult.Text = (num1+num2).ToString();
            }
            catch ( Exception ex)
            {
                lblResult.Text = ex.Message;
            }
        }


  • 需求二:在输入数字时,能直接看到结果而无需点击“=”按钮。
    1. 为输入框添加 TextChanged 事件,并将原本按钮的事件复制到两个输入框的 TextChanged 事件中:
        private void txtNumber1_TextChanged( object sender, EventArgs e)
        {
            try
            {
                int num1 = Convert.ToInt32(txtNumber1.Text);
                int num2 = Convert.ToInt32(txtNumber2.Text);
                lblResult.Text = (num1 + num2).ToString();
            }
            catch ( Exception ex)
            {
                lblResult.Text = ex.Message;
            }
        }
  • 需求三:将雷同的用于相加的方法提取用于复用。
    1. 选中代码,右键菜单>重构>提取方法Add()
  • 需求四:将窗口的数据输入与数据处理分离。
    1. 新增数据处理类MathOpt,并把权限改成public;
    2. 增加纯粹用于数据处理的方法Add;
    3. 在原来的类frmAdd中,实例化MathOpt类:private MathOpt calculator = new MathOpt();
    4. 在Add方法中将 lblResult.Text = (num1 + num2).ToString();  替换为 lblResult.Text=calculator.Add(num1, num2).ToString(); ;
    • 好处:Add方法中只与界面相关,并不涉及数据的处理
  • 需求五:(迈向组件化开发的重要一步)
    1. 将数据处理的代码做成程序集
      1. 添加新类库MathLibrary:
      2. 将MathOpt类复制到MathLibrary类库中,并修改命名空间使其匹配,并将多余的类删除;
      3. 编译;
      4. 在需要该类库的项目添加MathLibrary的引用。

小结:
  1. 不要不功能代码直接写到事件响应代码中,而是用调用函数的方式(减少代码重复);
  2. 尽可能少地编写重复代码,将重复的代码编写成组件以复用;
  3. 事件界面代码与功能代码分离;
  4. 尽量复用二进制形式的程序集,而不是复用源代码,即不该直接拷贝代码,而是引用已经编译好的类库。


.NET组件化开发技术

程序集(Assembly)
  • .NET Framework中基本的软件模块,它可以包容不限数目的类型,其常见的载体为一个或多个DLL文件,也可以是一个可独立执行的EXE文件。
  • 程序集和命名空间是多对多的关系。一个命名空间可以包含多个程序集,一个程序集也可以分布在多个命名空间中。
  • 一个项目如果需要使用特定程序集中的类型,需要添加对此程序集的“引用(Reference)”。

程序集的内部结构

  • 程序集大致分为两种:
    • 单文件程序集(占绝大多数)
    • 多文件程序集,多用于国际化程序设计时,根据实际情况组合程序集实现国际化多语言。
  • 程序集主要组成部分:元数据、IL代码、资源。
    • IL代码:有.NET编译器编译生成,将编程语言代码转换为IL代码,是程序集实现功能的主体。
    • 程序集元数据:程序集的公用信息。
    • 类型数据:该程序集定义了哪些类、接口、方法、属性、字段、事件等信息
  • 使用ildsam可以查看程序集元数据。

组件设计的“对外接口最小化”原则
  • 一个程序集中,可以放置任意多个类,但仅有需要为程序集外界使用的类,才设置为“公有(public)”,以实现程序集的信息封装。
  • 而公有类,需要使公有成员“越少越好”,这样的类才易于使用和维护。

组件间的“依赖性”
  • 含义:包容于某组件内部的类,需要调用另一个组件中的类以实现功能。
  • 这是由于类之间的依赖导致的。
  • 在设计各组件接口时,尽量避免和减少组件之间的耦合性。

解决方案示例:

  • UseDLL依赖于MyDLL和MyDLL2,UseDLLC、MyDLL和MyDLL2又依赖于.NET的基础组件System。
  • 在实际开发中,两个程序集之间的依赖关系应该要是“单向”的,不能是双向的,这是系统架构的关键点。
  • 具有相同的抽象级别的对个组件组成一个“层”,各个层之间的依赖关系也应是“单向”的。
  • 把多个组件分层,组件间建立“单向”的依赖关系,这种方式就称为“组件化的多层架构”,是当前软件系统最常见、最主流的软件架构。

避免出现组件循环依赖的情况,这样在编译时就会出错


  • 要消除这种循环依赖,应在设计时就避免;
  • 可以使用在组件间移动类的方式,消除组件间的循环依赖

组件的版本
  • 一个大型系统,需要注意其版本要一致。
  • 这里的版本是指:
    1. 组件运行时要求的软件系统平台的版本;
    2. 组件自身的版本。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:4612次
    • 积分:131
    • 等级:
    • 排名:千里之外
    • 原创:9篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类