分层[上篇]
最后更新于:2022-04-01 20:25:52
##一、前言
大家好,接近一年的时间没有怎么书写博客了,一方面是工作上比较忙,同时生活上也步入正轨,事情比较繁多,目前总算是趋于稳定,可以有时间来完善以前没有写完的系列,也算是对自己这段时间工作和生活上总结,同时也加深下自己对架构和
设计方面的理解,由于本人的写作水平有限,所以在书写的深度和书写的格式上还有很多的缺点,还希望大家多多指出。
##二、开篇
本篇我们将针对系统架构中的分层进行讲述,分析不同分层模式的优缺点及应用的场景,当然我们会结合一些案例来介绍这些分层,通过案例来证明各种分层的好处与优缺点,本篇作为开篇主要是介绍这个分层系列中会讲述到的几种分层模式实践,
由于很多分层模式也是自己在工作过程中总结和经验积累下来的,可能存在个人理解或用法上错误之处,还请大家指出,我予以及时更正。
##三、内容提要
1、前言
2、开篇
3、本文提纲
4、分层模式
4.1、分层架构介绍
4.1、后端分层多层
4.1.1、普通三层架构
4.1.2、多层架构
4.2、前端分层模式
4.2.1、MVC模式
4.2.2、MVP模式
4.2.3、MVVM模式
5、结束语
6、系列进度
7、下篇预告
##四、分层模式
4.1、分层架构介绍
架构首先是分为不同层次的和不同视图的,例如架构有五种视图:逻辑视图、物理视图、数据视图、运行视图、开发视图。我们今天不讲解这几个不同的视图,而是讲解分层对于软件设计的意义及关注点,之前我也发过一片单机软件架构的文章,文
章中提到了一个软件从简单到复杂的全过程,而软件架构也是一个迭代的过程,是一个循序渐进,不断完善的过程。
我们今天交流的主要是逻辑纬度的分层,关于物理视图的分层,本篇先不讲解,因为那块更复杂,同时也更重要,对于大型的互联网软件或大型的互联网网站,更关注的是物理架构方面的设计。下面我们就来针对当前的一些分层模式来进行讲解,并
且进行简要的分析和应用场景介绍。
4.2、后端分层架构
一、普通三层架构
三层架构(3-tier architecture) 通常意义上的三层架构就是将整个业务应用划分为:表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)。区分层次的目的即为了“高内聚,低耦合”的思想。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fdb82d1.png "image")](http://images.cnitblog.com/blog/46256/201312/24222637-f3f016ce26bf4da3ba3958992907d742.png)
三层架构图
对于传统的三层架构图,可能因为大家在实际的场景中,因为大家对这些分层运用的不同,会出现适应的场景的不同,而且有很多的大型软件或项目,都是采用三层架构,我们可以通过引入一些开源的组件或自定义组件来构建非常灵活或扩展性很强
的分层结构,虽然是3层架构,但是却可以满足大部分的场景。
A、场景:
最原始的三层结构可能如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fddffc1.png "image")](http://images.cnitblog.com/blog/46256/201312/24222639-3b3e215e16b84a87ac63e53cf4c234fd.png)
ThreeArchitecture.Entities:实体定义层,该层主要是完成各分层间数据传递并且最终通过该实体实现DAL层与数据库交互的数据传输。
ThreeArchitecture.DAL:数据访问层,通过调用实体层,通过Ado.net编程,实现数据持久化,例如可以支持多种数据库,sqlserver、oracle、mysql、sqlite.
ThreeArchitecture.BLL:业务逻辑层,通过调用实体层、数据访问层,实现整个业务系统的核心功能,完成系统业务的处理。
ThreeArchitecture.UI:用户界面交互层,用户通过该用户界面与业务系统进行交互,完成业务逻辑操作与交互。
根据上面的解决方案的分层及组织,下面针对以下几个场景来分析,分析三层架构中遇到的问题,应该如何解决这些问题。
1)、如果需要实现多数据库支持。我想业务系统能够从sqlserver向oracle数据迁移,或反之。
这样在现有的项目结构方式,就无法满足,但是我们可以增加新的接口层来实现这个要求。
例如可以通过如下项目方式来组织:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-21_574004559d3b0.png "image")](http://images.cnitblog.com/blog/46256/201312/24222640-7e9e7b598e58464b81f34bbf81102ce9.png)
修改原有的项目划分结构,加入DAL.Interface层次。定义数据访问接口,通过不同的数据访问实现,然后通过数据访问层工厂,来构建不同的数据库访问实例。
这块具体的代码我就不贴出了,应该比较简单。
同时原来的ThreeArchitecture.BLL 调用的不是直接调用数据库访问层实现,而是调用数据访问层接口。不依赖于具体的实现,而是依赖接口,这样可以实现解耦,提供了很强的扩展性。
2)、如果我要求业务逻辑层实现也不一定固定,例如在医疗行业的话,每个医院的业务系统或业务流程都不相同,那么假设我们希望沟通统一的UI界面,而不是随着业务逻辑的改变而修改UI,那么我们就需要进行如下的设计:
项目的结构方式类似上面的DAL层的变化。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-21_57400455c4343.png "image")](http://images.cnitblog.com/blog/46256/201312/24222641-fe6f2a2e3d95468e97823d2853780887.png)
在原来的基础上改进:
ThreeArchitecture.BLL.Interface:定义业务逻辑接口,主要目标是隔离UI与业务逻辑实现间的依赖关系,将实现代码调用修改为接口调用方式。
ThreeArchitecture.BLL.A:A场景下的实现,A的业务逻辑。
ThreeArchitecture.BLL.B:B场景下的实现,B的业务逻辑。
3)、纵向和横向扩展性需求场景,例如场景变化灵活性较高时,工厂模式无法很好应对,需要维护大量的工厂代码。
可以采用开源的相关组件,来实现解耦及隔离,例如 数据访问层可以采用Nhibernate或Entityframework来实现,关于Nhibernate的文章,园子里面已经有很多的文章介绍了,我就不介绍了,
引入Nhibernate以后,项目的结构,回到如下模式
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-21_57400455e514f.png "image")](http://images.cnitblog.com/blog/46256/201312/24222643-fc2172a550934b2b9d3272859fbb0c1d.png)
ThreeArchitecture.DAL.Nhibernate:NHibernate实现数据访问层接口,Nhibernate支持目录主流的大部分数据库,所以不需要按照1)中的方案去做,只需要实现一次即可。
ThreeArchitecture.DAL.EntityFramework:EntityFramework实现数据访问层接口,EntityFramework支持Oracle,SQLServer,其他的数据库支持的不太好。
在上面的场景中,例如在A场景下,我希望使用A业务层、B场景下使用B实现,而且,不希望系统中维护大量的工厂代码,那么我们就请出来当前架构或框架设计的核心组件IOC
IOC:控制反转(Inversion of Control,英文缩写为IoC)是一个重要的[面向对象编程](http://baike.baidu.com/view/10110.htm)的法则来削减计算机程序的耦合问题,也是当前主流框架的核心。 控制反转还有一个名字叫做依赖注入(Dependency Injection)。简称DI。
采用了IOC以后,接口和实现就可以通过配置的方式来动态的设置,而且调用的方式也变得更简单,不需要其他复杂的代码设定,目前市面上的IOC容器很多,我了解的主要是以下几种:
Unity:微软的轻量级IOC容器。提供了比较强的注册和动态查找机制,同时提供了强大的AOP,几乎无所不在。
Autofac:Autofac是一款IOC框架,比较于其他的IOC框架,如Spring.NET,Unity,Castle等等所包含的,它很轻量级性能上也是很高的
Spring.NET:参考java的sprint 框架的.net平台下的实现,比较强大。
Castle:Castle是针对.NET平台下的一个非常优秀的开源项目,从数据访问框架 ORM到依赖注入容器,再到WEB层的MVC框架、AOP,基本包括了整个开发过程中的所有东西,为我们快速的构建企业级的[应用程序](http://baike.baidu.com/view/330120.htm)提供了很好的服务
Ninject:是一个快如闪电、超轻量级的基于.Net平台的依赖注入框架。它能够帮助你把应用程序分离成一个个松耦合、高内聚的模块,然后用一种灵活的方式组装起来。通过使用Ninject配套你的软件架构,那么代码将会变得更加容易编写、重用性强、
易于测试和修改。
关于上面介绍的部分IOC容器的用法整体上来说都差不多,具体的大家可以网上搜索下,案例和demo比较多。
二、多层架构
上面介绍了普通的三层架构,多层架构顾名思义就是在三层架构之上,通过扩展及应用场景的挖掘,衍生出来的适应不同场景的架构模式,下面我主要是来介绍以下几种多层架构模式
A、服务层模式
在上面介绍的3层架构模式中,存在一个缺陷,如果我们构建的软件或系统支持分布式或者需要对外提供服务的时候,这个场景就无法满足了,所以这个时候服务层就出现了,就是在BLL层的基础上进行包装,包装成可以对外提供调用的分布式服务。
经过改造后的项目结构如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-21_574004560b35d.png "image")](http://images.cnitblog.com/blog/46256/201312/24222644-55626cd4313f4876af26157b1f01dab4.png)
在项目中加入了03.解决方案文件夹,同时添加项目 ThreeArchitecture.Service项目。
ThreeArchitecture.Service:主要是提供几个作用:1、将业务逻辑层进行封装,对外提供业务服务调用。2、通过外观模式,屏蔽业务逻辑内部方法。3、降低业务逻辑层与UI层的依赖,业务逻辑接口或实现的变化不会影像UI层。4、降低UI层调用的请求次
数及数据往返。
在上面的结构中,我们说了Service层次的作用,目前还少加入了一层,DTO(数据传输对象层),该层负责屏蔽后端的实体层,将UI层需要的数据进行重新的定义和封装,在实际的业务场景下,后端实现或存储的数据远比用户需要的数据要庞大和负责,所
以前端需要的数据相对来说要么是组合的,要么是抽取的,不是完整的,因为我们在设计数据存储格式上都会有一些额外的设计和考虑。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-21_574004562952b.png "image")](http://images.cnitblog.com/blog/46256/201312/24222646-7bff1f540ccb4bbb876cdf7e906778c6.png)
加入了ThreeArchitecture.DTO层后,前端的UI层,只是知道DTO的存在,同时前端需要的数据都在一个Dto中,这样,每次调用服务层的时候,只需要调用一次就可以完成所有的业务逻辑操作,而不是原来的直接调用业务逻辑层那样的,需要调用多
次,对于分布式场景下,减少服务调用的次数,尤其重要。
B、DDD架构模式:
[![image](image/56a5c14d8fa38.png "image")](http://files.dotblogs.com.tw/jed/1007/DomainDrivenDesign_964D/image_6.png)
Presentation Layer: 负责与客户端进行交互
Application Layer: 负责协调领域层之间的交互
Domain Layer: 软件的核心,所有相关的Domain information都在这,可以看成是Business Logic Layer,但不完全是
Infrastructure Layer: 負責各層之間的交互溝通、資料存取、安全性管理及通用Library
更常见的是如下层次
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-23_56a2eb4ae9d0c.gif)
我们建议的方式如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-21_57400456584fb.jpg)
Repository层使用ORM映射或SQL命令等方式把持久化数据转化为领域对象,然后根据业务逻辑设计对应领域层服务Domain Service 。接着应用层进行操作上的协调,利用Repository、领域模型、领域层服务Domain Service 完成业务需要,再通过数
据转换器把领域对象Domain Object转化为数据传输对象DTO。最后,利用远程通讯技术把应用层的服务(Application Service)对外开放。
注意留意的是SOA系统中,UI表现层与Application Service应用层服务是实现分离的,表现层可以同时调用多方的远程服务来完成工作。
在上面的架构中还可以加入领域事件、查询接口、分布式服务层,来灵活运用和组合,来解决项目中适应场景的不同。
4.3、前端分层架构
A、MVC架构模式
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑和数据显示分离的方法组织代码,将业务逻辑被聚集到一个部件里面,在界面和用户围绕数据的交互能被改进和个性化
定制的同时而不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-21_5740045678c0b.jpg)
目前在主流的框架中都支持该模式,例如构建winform程序中可以通过MVC模式来分离界面层中的控件与后端服务间的交互。降低耦合及依赖。
web上通过asp.net MVC框架来实现前端页面及后端控制器之间的隔离。
##### 视图
视图是用户看到并与之交互的界面。对老式的Web应用程序来说,视图就是由HTML元素组成的界面,在新式的Web应用程序中,HTML依旧在视图中扮演着重要的角色,但一些新的技术已层出不穷,它们包括Adobe Flash和像XHTML,XML/XSL,WML
等一些标识语言和Web services.
MVC好处是它能为应用程序处理很多不同的[视图](http://baike.baidu.com/view/71981.htm)。在视图中其实没有真正的处理发生,不管这些数据是联机存储的还是一个雇员列表,作为视图来讲,它只是作为一种输出数据并允许用户操纵的方式。
##### 模型
模型表示企业数据和业务规则。在MVC的三个部件中,模型拥有最多的处理任务。一个模型能为多个视图提供数据,由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。
##### 控制器
控制器接受用户的输入并调用模型和视图去完成用户的需求,所以当单击[Web](http://baike.baidu.com/view/3912.htm)页面中的超链接和发送[HTML表单](http://baike.baidu.com/view/3488030.htm)时,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数
据。
ASP.NET MVC
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-21_5740045691ff5.png "image")](http://images.cnitblog.com/blog/46256/201312/24222649-ac425b4781d04b08a468476d540fc53d.png)
关于具体的代码,大家可以尝试新建一个MVC的应用程序,微软提供的默认的MVC的代码模版中就有相关的示例代码,具体的我就不介绍了。
Winform的MVC模式
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-21_57400456b8816.png "image")](http://images.cnitblog.com/blog/46256/201312/24222654-49a1721f6a6a44bda5d3979b2c8cb0aa.png)
winform的MVC模式,主要是通过事件的方式来实现。
B、MVP架构模式
MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间
的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。
在MVC里,View是可以直接访问Model的!从而,View里会包含Model信息,不可避免的还要包括一些业务逻辑。 在MVC模型里,更关注的Model的不变,而同时有多个对Model的不同显示,及View。所以,在MVC模型里,Model不依赖于Vie
w,但是View是依赖于Model的。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-21_57400457066fd.png)
1、View和Model完全解耦,两者不发生直接关联,通过Presenter进行通信。
2、Presenter并不是与具体的View耦合,而是和一个抽象的View Interface耦合,View Interface相当于一个契约,抽象出了对应View应实现的方法。只要实现了这个接口,任何View都可以与指定Presenter兼容,从而实现了P Logic的复用性和视图的无缝替换。
3、View在MVP里应该是一个“极瘦”的概念,最多也只能包含维护自身状态的逻辑,而其它逻辑都应实现在Presenter中。
总的来说,使用MVP模式可以得到以下两个收益:
1、将UI和P Logic两个关注点分离,得到更干净和单一的代码结构。
2、实现了P Logic的复用以及View的无缝替换。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-21_574004571bbfc.png "image")](http://images.cnitblog.com/blog/46256/201312/24222657-64d1c39ae7a54b728db71edf8126c248.png)
展示器层作为核心的控制,实现view和model之间的完全解耦。关于该架构设计的具体demo 后面来介绍
C、MVVM架构模式
MVVM是Model-View-ViewModel的简写。
[微软](http://baike.baidu.com/view/2353.htm)的WPF带来了新的技术体验,如Sliverlight、音频、视频、3D、动画……,这导致了[软件](http://baike.baidu.com/view/37.htm)UI层更加细节化、可定制化。同时,在技术层面,WPF也带来了 诸如Binding、Dependency Property、Routed Events、Command、DataTemplate、C
ontrolTemplate等新特性。MVVM(Model-View-ViewModel)框架的由来便是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。它立足于原有MVP框架并且把WPF的新特性揉合进去,以应对客户日
益复杂的需求变化。
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大优点
1. 低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
2. 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
3. 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xaml代码。
4. 可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-21_574004573e755.png)
1. 视图(View)
视图负责界面和显示。它通过DataContext(数据上下文)和ViewModel进行数据绑定,不直接与Model交互。 可以绑定Behavior/Comand来调用ViewModel的方法,Command是View到ViewModel的单向通行,通过实现Silverlight提供的IComand接口来实现绑定,让View触发事件,ViewModel来处理事件,以解决事件绑定功能。
2. 视图模型(ViewModel)
视图模型主要包括界面逻辑和模型数据封装,Behavior/Command事件响应处理,绑定属性定义和集合等。它是View和Model的桥梁,是对Model的抽象,比如:Model中数据格式是“年月日”,可以在ViewModel中转换Model的数据为“日月年”供View显示。
实现视图模型需要实现Silverlight提供的接口INotifyPropertyChanged, INotifyPropertyChanged接口用于实现属性和集合的变更通知(Change Notifications)。使得在用户在视图上所做的操作都可以实时通知到视图模型,从而让视图模型对象有的模型进行正确的业务操作。
View的代码隐藏(Code-Behind)部分可能包含界面逻辑或者应用逻辑的代码,这些代码会很难进行单元测试,应根据具体情况尽量避免。
3. 模型(Model)
Model与MVC模式一样,Model用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。它具有对数据直接访问的权利,例如对数据库的访问,Model不依赖于View和ViewModel,也就是说,模型不关心会被如何显示或是如何被操作,
模型也不能包含任何用户使用的与界面相关的逻辑。Model在实际开发中根据实际情况可以进行细分。比如在广州市城乡规划资源平台就将Model将Service和Reposiroty结合为WCF服务由ViewModel进行调用。
一般来说实际的项目中会采用以下的模式来做,而不是直接采用传统的MVVM模式,而是结合MVP或MVC模式来做。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-21_574004575bac9.png "image")](http://images.cnitblog.com/blog/46256/201312/24222700-c7b65ab1a5564b0a9033c755d9c46b89.png)
上图中的P层是整个项目的核心,负责处理View层显示的数据来源及用户操作的响应的处理,通过绑定viewModel中的command的处理来与后端服务进行交互,展示器层会调用后端的WCF服务来读取数据,也就是读取DataModel 然后修改View
Model。通过WPF提供的通知机制,来修改view的呈现。
MVC、MVP、MVVM对比
##五、结束语
通过上面软件架构模式的介绍,大家对这些软件架构的模式有了一定的了解,后面的关于分层中篇、后篇就是结合一些具体的案例来进行代码的编写的讲解和实现。当然如果大家有比较感兴趣的议题,也请提出来,可以根据这些议题,然后将上面介
绍的这些模式来去实现。
也欢迎大家针对我提出的这些思路进行讨论,提出不同的看法和想法,另如果需要更深层次的讨论,可以QQ与我联系。
关于上面介绍的只写架构模式,我已经全部实现,如果需要相关的技术支持,请找我,或者您有什么建议或意见,都请联系我。
';
标题 | MVC | MVP | MVVM |
特点 | 高内聚、低耦合-一个控制器可以控制多个视图 | 高内聚、低耦合-解决MVC中View依赖Model的问题 | 高内聚、低耦合-解决winform中存在的问题。解决view和Model之间的依赖,屏蔽view改变带来的影响。 |
应用场景 | 前端与后端交互架构设计(CS或BS) | 前端与后端交互架构设计(CS或BS) | 前端与后端交互架构设计-WPF或Web通过js实现 |
系统建模[下篇]
最后更新于:2022-04-01 20:25:49
### 一、上章回顾
上一篇:[系统架构师-基础到企业应用架构-系统建模[中篇](下)](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/14/1826314.html) 中我们主要讲解了部署图、活动图,我们在这里也是参考上篇的形式,这里不再详细介绍。上篇主
要讲解了下面2类建模图:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fb8ea98.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_2.png)
### 二、摘要
本文将讲解其他的几个类型的建模图当然只是简单的讲解,并且将结合B2C电子商城系统进行分析通过使用我们已经讲解的建模图为例。分析系统可划分的子功能
模块,每个功能模块内部的运行步骤等等。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fbb1fb2.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_4.png) [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fbcca35.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_6.png)
上面的2个不同类型的进行划分的建模图,本章将对上述6个建模图进行分别举例讲解。
### 三、本章内容
1、上章回顾。
2、摘要。
3、本章内容。
4、结构图。
5、行为图。
6、本章总结。
7、系列进度。
8、下篇预告。
### 四、结构图
#### 1、对象图
首先、我们闲来讲解对象图。对象图用来描述系统的各个对象在某一时刻的状态。对象和类图一样他们是静态结构图。他们是从实际的或者原型化的场景去表达
的。对象图显示了某一时刻对象与对象的关系。一个对象图可以看作类图的特殊用例,类图中的关系同样适用在对象图中。可以这样理解,对象图就是类图的实例。对
象图是有生命周期的,因此对象图只在某个时间段内存在。
对象图中的元素在类图中都可以找到,只是把类图中的类元素换成对象即可。而类图中类元素之间的关系,在对象图中同样适用。这里不在复述。如果对类图不
是特别的熟悉,请看这篇文章中的讲解:[系统架构师-基础到企业应用架构-系统建模[上篇]](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/10/1822887.html)。
下面讲解对象图的举例:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fbe06f1.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_8.png) 这里的对象是指某个类的实例。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fbf2a0c.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_10.png) 这样的格式表示了某个类的实例的格式,冒号“:”后面跟着类名,也就是这里的“父类”。另外还必须加上下划
线。
对象首先是一个确定,所以一般情况下,对象属性一般把值直接列出来。如下形式:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fc0eb8e.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_12.png)
对象图中的所有的对象名可以为空,但是为了更好的标识对象图中的对象,不建议这么做,并且如果未指定对象名那么必须指定该对象所属的类格式如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fc20a1c.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_14.png) 没有对象名的对象实例。
下面以B2C中的订单系统中的新订单的状态为例,讲述下各对象的状态。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fc35753.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_16.png) 这里的关系表示的是组合关系
上图中的订单信息的状态:订单(新订单)-物流信息(未发货)-支付信息(未支付)-产品状态(产品信息)。
#### 2、包图
包图就是由包与包之间的关系组成的。
包图也是一种静态结构,包可以拥有的元素:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fc4f7df.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_18.png)
我想上面的元素大家都是有所了解的,我这里就不一样举例说明了,下面通过一个例子来显示如何使用包图。
包的访问限制:与我们平时了解的3个访问权限设置关键字用法相同。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fc6d655.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_20.png)
包与包之间的关系:
a、引入与访问依赖:首先这个关系与平时我们说的类的继承关系是不同的.包括包的访问域不能继承。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fc98024.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_26.png) 用于在一个包中引入另一个包输出的元素,因此A依赖B,包A引入包B中的B方法。B这里的访问权限是公共的。A中的方法是保护的。
b、泛化关系:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fcae751.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_28.png) 泛化关系描述了一种继承关系。即基类与特殊类之间的关
系,途中描述的意思是只要是包A出现的位置都可以用包B替换。
#### 3、组合结构图
组合结构图:以结构化的方式给出类型的内部结构。组合结构图是一种静态结构,它显示了一个类型内部的成员及成员之间的关系。组合结构图可以这样理解,
就是描述类的内部结构及成员之间的调用关系的建模图。组合结构图用于扑捉类的内部细节,描述了对象如何在某个类中协同工作。
组合图中其实就是描述类的内部的结果,基本上的元素有:类、对象,其他等,具体的关系请参考类图中的关系。
组合图实例:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fcc37df.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_34.png) 上图显示了产品与产品品牌与产品分类的组合关系。产品品牌与产品分类是关联关系(关联关系可
以是1:N),通过一条直线来链接。如果有不清楚的地方请看类图的相关介绍:[系统架构师-基础到企业应用架构-系统建模[上篇]](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/10/1822887.html)。
### 五、行为图
#### 1、通信图
在UML建模中除了顺序图(序列图)可以表示对象之间的交互外,通信图也可以完成通用的描述。一般情况下,二类图可以进行互转。
首先、我们先来分析下2类图的不同。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fced457.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_38.png)
我们还是先来看下通信图中的元素:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fd1ccf3.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_42.png)
上图中的主要组成元素是对象。对象之间的关系,通过链接来完成。然后通过一个带有实体三角形的线段指向要发送消息的对象。
下面来解释下对象之间的关系。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fd36ae6.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_46.png)
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fd4a37c.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_52.png) 还有就是消息给自己发送的特殊消息。
返回消息的类型:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fd5e4c5.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_48.png)
下面我们来简单举例如何说明:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fd70c0d.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_50.png) 上图中简单描述了发送邮件的过程。我们可以看出通信图相比顺序图更注重对象之间的
链接关系。我们通过通信图能够知道一个系统中的某个流程中各对象直接的链接关系及传递的完整信息传递过程。
首先、我们闲来讲解对象图。对象图用来描述系统的各个对象在某一时刻的状态。
#### 2、时间图
时间图:主要用来描述一段时间内对象的行为(状态的变化,执行的动作等等)。主要用来模拟即时系统模型。与对象图类似,不同的是时间图描述的一个时间段,而
对象图描述的一个时间点。对象图关心对象的状态,而时间图关心的是对象的行为。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fd87e94.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_54.png) 这里设置了定时器之后,对象的状态将会从A,在定时器时间到达后自动的跳转
到状态B。这里表示的是定时器来控制状态的迁移。
时间图中支持异步信息,时间图采用垂直图的方式来描述系统的执行顺序。
时序图等于是在序列图(顺序图上)加上时间的限制就构成了时间图。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fd9d37e.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/32f26f83aa02_A050/image_58.png) 从垂直的角度来看,就是说A调用B先于B返回值给A,从时间图上就可以清晰的看出来对象的行
为。 一般情况下我们可以通过序列图来完成相应的描述。除非需要定义一个时间段的对象时才会用到时间图。包括某个对象到某个对象的调用都可以通过时间限制来进
行行为的控制等。
### 六、本章总结。
本章中主要简单的讲述了几类UML2.0语言相比UML1.0新增的几类建模图,虽然我们平时可能用的比较少,但是某些特定的领域范围,通过这些图可能更能清晰的
表达抽象模型。
1、对象图:描述系统在某一时刻的状态。
2、包图:描述系统中的某个模块的内部组成结构,是由元素及元素之间的关系构成的。
3、组合结构图:以结构化的方式描述了系统中的某个类型的内部结构。
4、通信图:描述了对象之间的交互与顺序图不同的是,交互图更关注对象之间的链接及通信。
5、时间图:描述了在一个时间段内的对象的行为。
当然具体的建模图如何使用及在实际的项目中如何去应用分析,这才是最主要的目的,当然这就需要理论结合实际来达到学以致用的效果。下一篇,我讲专门的讲
解针对B2C电子商城为例,详细的剖析UML建模的具体应用。
### 七、系列进度。
##### 前篇
1、[系统架构师-基础到企业应用架构系列之--开卷有益](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/07/1821012.html)
2、[系统架构师-基础到企业应用架构-系统建模[上篇]](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/10/1822887.html)
3、[系统架构师-基础到企业应用架构-系统建模[中篇](上)](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/11/1824084.html)
4、[系统架构师-基础到企业应用架构-系统建模[中篇](下)](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/14/1826314.html)
5、[系统架构师-基础到企业应用架构-系统建模[下篇]](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/16/1828169.html)
6、系统架构师-基础到企业应用架构-系统设计规范与原则[上篇]
7、系统架构师-基础到企业应用架构-系统设计规范与原则[下篇]
8、系统架构师-基础到企业应用架构-设计模式[上篇]
9、系统架构师-基础到企业应用架构-设计模式[中篇]
10、系统架构师-基础到企业应用架构-设计模式[下篇]
##### 中篇
11、系统架构师-基础到企业应用架构-企业应用架构
12、系统架构师-基础到企业应用架构-分层[上篇]
13、系统架构师-基础到企业应用架构-分层[中篇]
14、系统架构师-基础到企业应用架构-分层[下篇]
15、系统架构师-基础到企业应用架构-表现层
16、系统架构师-基础到企业应用架构-服务层
17、系统架构师-基础到企业应用架构-业务逻辑层
18、系统架构师-基础到企业应用架构-数据访问层
19、系统架构师-基础到企业应用架构-组件服务
20、系统架构师-基础到企业应用架构-安全机制
##### 后篇
21、单机应用、客户端/服务器、多服务、企业数据总线全解析
22、系统架构师-基础到企业应用架构-单机应用(实例及demo)
23、系统架构师-基础到企业应用架构-客户端/服务器(实例及demo)
24、系统架构师-基础到企业应用架构-多服务(实例及demo)
25、系统架构师-基础到企业应用架构-企业数据总线(实例及demo)
26、系统架构师-基础到企业应用架构-性能优化(架构瓶颈)
27、系统架构师-基础到企业应用架构-完整的架构方案实例[上篇]
28、系统架构师-基础到企业应用架构-完整的架构方案实例[中篇]
29、系统架构师-基础到企业应用架构-完整的架构方案实例[下篇]
30、系统架构师-基础到企业应用架构-总结及后续
### 八、下篇预告。
下一篇将会已我比较熟悉的B2C电子商城来深入的剖析,如何使用UML建模工具去分析一个系统及如何分析一个模块的流程,包括部署等等。通过我们已经讲过的
UML建模图形来结合实例来讲解。如果大家有好的意见和建议可以及时反馈,谢谢您的宝贵意见。
### 后语
希望看完本章的朋友可以从本篇中学到相应的UML建模知识,懂的人可以巩固下UML知识,本篇希望能够抛砖引玉,希望大家能够多提出宝贵意见。由于是本人
平时工作中的理解与总结,不足之处再所难免,还请大家批评指出!如果您有什么意见或建议,请多多提出!大家的支持就是我的最大动力!
';
系统建模中篇
最后更新于:2022-04-01 20:25:47
### 一、上章回顾
首先、我们先来回顾下,上篇讲解的内容,加深下印象。上篇我们主要讲解了3个建模图形分别是:顺序图(序列图)、组件图、状态图。
具体功能描述如下图:这里不详细解释,如果不清楚请看:[系统架构师-基础到企业应用架构-系统建模[中篇](上)](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/11/1824084.html)
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f99c645.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_2.png)
由于全部放在一篇中篇幅太长了,所以分开讲解。
### 二、摘要
本文主要讲解:UML建模图中的活动图、部署图等
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f9b54a8.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_4.png)
上图中就是本章要讲解的内容,本质将仔细的剖析,部署图与组件图的关系与区别,活动图与状态图的关系与区别。
### 三、本章内容
1、上章回顾。
2、摘要。
3、本章内容。
4、建模中的抽象模型图之部署图、活动图。
5、本章总结。
6、系列进度。
7、下篇预告。
### 四、抽象模型图之部署图、活动图
#### 部署图
首先,我们先来讲解部署图。部署图主要是用来描述一系列组件部署到节点运行的结构。部署图显示了系统运行时的结构。一般情况下部署图帮助我们来理解分布
式应用系统。同时部署图还传达了构建应用系统的软件与硬件元素的配置及部署方式。
部署图中的基本元素:
1、节点:这里就是指组件运行的环境。可以是软件(操作系统、其他等)或硬件资源(计算机,其他硬件)。
UML建模语言中的通用图形化表示为:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f9d3584.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_8.png)
2、节点实例:节点实例与节点的区别就是有下划线和冒号,节点实例必须紧跟冒号,当然这个节点实例名称可以为空,节点必须要有。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f9e442e.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_10.png)
3、组件容器:一个节点可以包含其他节点,可以是组件,也可以是节点。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fa03070.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_14.png)
4、节点之间的关系
(1)、单向依赖:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fa1aa51.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_16.png)
上图表示 查询统计组件,通过.net提供的ADO.NET访问SQLServer2005数据库。
(2)、双向依赖:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fa32275.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_18.png)
上图表示:产品管理模块会把数据写入到数据库中,同时产品管理中的信息会从数据库中读取,双向依赖。
(3)、通信:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fa48449.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_20.png)
上图表示:应用软件系统与数据库通过.NET提供的方式相互通信,个人理解任务就是双向通信(双向依赖)[错误之处,还请高人指出]。
5、实例讲解:
下面我们已一个简单的系统B2C来进行讲解:
我们先来看看B2C系统中的相应节点:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fa60558.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_26.png)
客户端通过浏览器访问B2C站点,首先进入会员管理,如果注册,则进入到注册系统。会员管理中完成对采购的管理、支付、发布等。
节点描述:
浏览器:通过键入网站地址访问B2C站点。这是与B2C系统交互的唯一入口。
注册系统:完成用户的注册与数据库通信。图上并未画出,所有的节点除了浏览器不需要直接与数据库交互外,其他的模块都需要与数据库通信。
会员管理:完成会员中心的管理。会员的个人信息,开店的店铺信息,收货地址等等信息的管理,我的采购,我发布的产品等等。
采购系统:系统中的子功能,用于完成买家的产品采购。
发布系统:主要为卖家提供服务,发布产品信息等。与数据库通信
支付系统:完成支付交易的操作。与个人账户进行通信。
当然这里只是举个简单的例子,其他的内容,比如前台的展示等等,这些目前都没有考虑其中,也没有仔细分析,这里只是达到介绍的目的。
6、总结
通过上面的讲解相信大家对部署图已经有了基本的认识,部署图主要是用来完成将组件部署到节点上运行的结构。从整体上描述了,系统运行时的结构。部署图是
必须要掌握的建模图。
#### 活动图
活动图主要是用来描述系统的动态行为,从一个活动到另一活动的控制流。活动图的本质是流程图,但是与流程图又有所不同。在本小节中将会详细的讲解活动
图与流程图的本质的区别及活动图与状态图的区别。
按照惯例,我们先来看看活动图的元素:
1、动作状态:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fa7a648.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_28.png)
通过用圆形边的长方形来表示一个动作状态。动作状态有几个特点:原子性(要么执行,要么不执行)、不可中断的操作,并且此次动作完成后一定转向到另外一种
状态。 动作状态是构造活动图的最小单位。
状态图区别:
a、活动图中动作状态可以有入转换与出转换,意思就是说可以从当前状态转向到另外一个状态,也可以从另外一个状态转换到当前状态。图形化的表示如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fa8c10f.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_32.png) B动作状态,可以有入转换A,出转换C。
动作状态必须至少有一个出转换,转换都是以内部的完成为起点,与外部事件无关。
实心圆:代表起始状态。
环形内的实心圆:代表结束状态。
b、动作状态与状态图不同的是,动作状态不能有入口动作与出口动作。更不能有内部转移。
2、活动状态:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996faa361b.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_34.png)
通过二个半圆与一个长方形组合起来来标识活动状态。
活动状态首先可以被分解成多个子活动或者多个子动作状态。活动状态他不像动作状态是原子性的。活动状态是非原子性。活动图内部的活动,可以用另外一个
活动图来表示。活动状态可以看作多个动作状态和多个子活动的组合。
活动状态与动作状态不同,动作状态是活动状态的一个特例,当某个活动状态只有一个动作状态时,这个活动状态就是一个动作状态。活动状态可以有入口动作
和出口动作。还可以有内部转移。因为活动图是多个子活动和多个动作状态的组合,所以本来动作状态直接的转向就可以看作是内部转移了,所以就很好理解了。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fab60fb.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_38.png)
上图已经基本表示出来了活动状态中的动态状态的转移等。我相信大家都能理解。
3、动作节点之间的关系
a、控制流:[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fad1462.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_40.png) 与状态图中的转向相同,活动图也使用一个带箭头的线段,箭头指向要转入的状态。
b、分支:[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fb013d7.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_46.png) 活动状态从A分支出来活动状态B、C,
c、合并:[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fb17a76.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_48.png) 活动状态B从活动状态A与C合并后得到。
d、泳道:泳道将活动图中的多个活动划分成多个组。并且把每一组活动都由对象来负责组织业务,泳道区分了负责活动的对象。并且泳道明确的表
示了哪些活动是由哪些对象进行的。泳道通过垂直线来区分。而2个垂直线分割的区域即是一个泳道。上面的解释可能有点绕,说白了泳道即是上面说的对象,对象就是
泳道。把不同的泳道就叫一个对象。每个活动状态在有泳道的活动图中,只能属于一个泳道。
下面来看有泳道的图例:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fb2d5f2.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_50.png) 上面有2个泳道,分别是我是泳道1,我是泳道,并且我是泳道1中的D与我
是泳道中的活动状态A有转向关系。
e、对象流。
对象流是对象与动作状态或者活动状态直间的依赖关系。表示动作使用对象或者动作对对象的影响。一般我们在使用中,我们可以把对象通过依赖关系与动作状态或者活动状态进行链接。
对象流的几个特点:
(1)、一般一个对象可以由多个活动状态或动作状态操作。
(2)、一个活动状态或动作状态的输出对象可以作为另一个活动状态或动作状态的输入。
(3)、一个对象可以在一个活动图中多次出现,但是有点需要注意,这个对象多次出现时表名该对象处于生命周期的不同时期。
包含对象流的活动图:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fb48bd4.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_52.png)
泳道M1中出现了对象。并且该对象与活动状态B有依赖关系。
#### 总结
本节中讲解了,活动图的基本知识,下面我们以我们平时比较熟悉的B2C业务,电子商城为例说明下,会员的产品管理流程。通过状态图的形式来表达。以巩固
下我们学习的成果。
例如B2C中的产品管理。首先必须是会员才能登入系统中,然后必须是我是卖家,然后才能进行发布产品的操作。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fb657f3.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_56.png) 会员先要开启店铺,设置权限后才能进行产品管理
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996fb77ba9.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/45870215679f_F638/image_58.png)
### 五、本章总结
本章主要讲述了部署图与活动图。现在我们回顾下本章要点。
部署图:主要用来描述一系列组件部署在节点上运行的结构,是系统运行是的结构的描述。主要用于软件系统的
活动图:主要用来描述系统的动态行为,从一个活动转换到另外一个活动状态。通过一系列的操作将业务流程通过工作流的形式来描述。一系列操作就是一系列
的活动状态。
### 六、系列进度。
##### 前篇
1、[系统架构师-基础到企业应用架构系列之--开卷有益](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/07/1821012.html)
2、[系统架构师-基础到企业应用架构-系统建模[上篇]](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/10/1822887.html)
3、[系统架构师-基础到企业应用架构-系统建模[中篇](上)](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/11/1824084.html)
4、[系统架构师-基础到企业应用架构-系统建模[中篇](下)](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/14/1826314.html)
5、系统架构师-基础到企业应用架构-系统建模[下篇]
6、系统架构师-基础到企业应用架构-系统设计规范与原则[上篇]
7、系统架构师-基础到企业应用架构-系统设计规范与原则[下篇]
8、系统架构师-基础到企业应用架构-设计模式[上篇]
9、系统架构师-基础到企业应用架构-设计模式[中篇]
10、系统架构师-基础到企业应用架构-设计模式[下篇]
##### 中篇
11、系统架构师-基础到企业应用架构-企业应用架构
12、系统架构师-基础到企业应用架构-分层[上篇]
13、系统架构师-基础到企业应用架构-分层[中篇]
14、系统架构师-基础到企业应用架构-分层[下篇]
15、系统架构师-基础到企业应用架构-表现层
16、系统架构师-基础到企业应用架构-服务层
17、系统架构师-基础到企业应用架构-业务逻辑层
18、系统架构师-基础到企业应用架构-数据访问层
19、系统架构师-基础到企业应用架构-组件服务
20、系统架构师-基础到企业应用架构-安全机制
##### 后篇
21、单机应用、客户端/服务器、多服务、企业数据总线全解析
22、系统架构师-基础到企业应用架构-单机应用(实例及demo)
23、系统架构师-基础到企业应用架构-客户端/服务器(实例及demo)
24、系统架构师-基础到企业应用架构-多服务(实例及demo)
25、系统架构师-基础到企业应用架构-企业数据总线(实例及demo)
26、系统架构师-基础到企业应用架构-性能优化(架构瓶颈)
27、系统架构师-基础到企业应用架构-完整的架构方案实例[上篇]
28、系统架构师-基础到企业应用架构-完整的架构方案实例[中篇]
29、系统架构师-基础到企业应用架构-完整的架构方案实例[下篇]
30、系统架构师-基础到企业应用架构-总结及后续
### 七、下篇预告。
下一篇中我们将会讲述:简单讲述其他的UML建模图,并且结合B2C实例,详细分析B2C系统应该具有的功能模块。及每个模块通过不同的建模图形的表示方
法,及如何在功能分析时使用恰当的建模图。
### 后语
希望看完本章的朋友可以从本篇中学到相应的UML建模知识,懂的人可以巩固下UML知识,本篇希望能够抛砖引玉,希望大家能够多提出宝贵意见。由于是本人
平时工作中的理解与总结,不足之处再所难免,还请大家批评指出!如果您有什么意见或建议,请多多提出!大家的支持就是我的最大动力!
';
系统建模中篇
最后更新于:2022-04-01 20:25:45
### 一、上章回顾
上篇文章主要简单的介绍了建模中使用的标准建模语言UML的相关内容,包括用例图与类图的使用方法及如何建模。相信大家对UML建模语言已经有了初步的认
识,还请大家谨记UML不同的建模图形的用处。比如,用例图主要用来描述系统的功能需求。类图主要用来描述实体间的关系。谨记这些就可以帮助我们在系统架构的
过程中深入的分析。
首先向大家道歉,上篇中有部分描述错误的地方,可能对大家造成一定的错误引导。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f75c40d.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_2.png) 这是上篇给出的图,我描述的是组合关系。
特别更正为:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f76d755.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_4.png) 这是正确的结果。箭头指向聚合类。描述的信息并无任何错误。希望能对大家指正。
### 二、摘要
本文主要从系统架构中的建模开始讲解,本文讲述的内容主要是我在工作和学习过程中的总结和经验,不足之处还请大家多多批评指出,有更好的建议也可以留言
说明。本意主旨是为不熟悉系统架构建模过程和不知道如何使用建模工具,或者不熟悉如何根据需求去建立模型的角度出发,简单的阐述了在系统架构的过程中我们应
该从什么样的角度出发去分析需求并且建立抽象模型。这应该说是架构师必备的技能。
本文由浅入深,本篇将简单的介绍如何使用使用UML建模中的各个结构图与行为图,去完成抽象模型的建立。
本文主要讲解以下几个建模图形:顺序图、组件图、状态图、活动图、部署图。当然本文也只是讲述了基本理论介绍及如何设计使用,系统架构师-基础到企业应
用架构-系统建模[下篇] 将会详细的讲解通过具体实例讲解如何使用这些已经介绍的抽象模型图形去描述。
### 三、本章内容
1、上章回顾。
2、摘要。
3、本章内容。
4、建模中的抽象模型图。
5、本章总结。
6、系列进度。
7、参考文献。
8、下篇预告。
### 四、建模中的抽象模型图。
#### 1、顺序图。
#### 介绍
顺序图也称序列图,主要用来系统中的某个流程的详细步骤。顺序图能够给出流程中一系列对象的交互顺序。通过顺序图可以让我们更好的了解如何实现某个用例
的方法。我们知道用例图用来描述系统的功能需求。而顺序图清晰的描述了某个用例也就是系统功能的的实现方法。
#### 详解
在顺序图中包含的元素:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f7801ed.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_12.png)
对象:用来标识流程中的详细步骤中的对象。
活动条:用来标识当前对象是活动的,如果想表示某个对象是活动的,那么必须使用一个虚线+活动图的形式来构建。
例如我们现在要标示一个简单的做公交车的刷卡流程:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f795614.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_14.png) IC卡刷卡操作。
相关解释说明:
公交卡,首先放在刷卡终端上,终端读取卡中的余额信息,然后刷卡终端与终端中的扣款程序对象交互,扣款程序根据读取的余额信息,与刷卡终端中的固定刷卡
金额对比,如果当前IC卡的余额大雨刷卡终端的固定金额则,扣除金额,并且返回一个消息,提示刷卡成功的操作。
途中的实线表示调用被调用对象的方法,虚线表示当被调用对象执行成功后,返回的虚线上表示返回值的逻辑名称,这样可以提高了可读性。
在公交卡与活动条之间,应有一个虚线链接。
在上图中我们使用了活动条,活动条作为生命线的一部分。我们并没有定义对象的创建和销毁,因此我们来看UML建模语言提供的描述对象的创建与销毁实例。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f7b3e47.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_18.png)
上图中的X符号的图标代表的时候对象的销毁。创建对象通过new来创建,上图中,我用中文描述“创建对象”来完成对象的创建,那么在生命线下的的X符号代
表销毁对象,从内存中移除对象。当然这个对象的销毁对不同的开发语言有这不同的处理方式。C++中的销毁对象,必须调用析构函数来销毁对象。C#与JAVA语言中
则只是说明当前需要销毁的对象没有被其他的对象引用,那么这类语言编译器提供垃圾回收器来完成回收。
注意:当某个对象引用了另外一个对象,该对象有责任销毁被引用对象并且必须显示销毁该被引用对象时,那么必须要显示的发送被引用对象销毁的通知消息。白
话文来说就是显示的调用被引用对象的销毁方法。
顺序途中的同步与异步。
顺序图中的同步与异步与我们平时书写代码中的同步与异步的解释意思差不多。这里不过多解释,通过图例说明:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f7cfa98.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image38.png) 客户去餐厅吃饭,首先要点餐,必须等待点餐完了才能上菜。意思就是可以这样简单描述。A简单调用B方
法,必须等待,等到B方法执行完毕后,继续执行。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f7e3d31.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_22.png) 函数A调用函数B,如果B需要的时间特别长,那么此时A可以去继续执行做其他的事情比如做和函
数C交互,等B函数执行完了,只需要回调通知A,B函数执行完了即可。在函数调用中的术语就是回调。
UML建模语言中同步与异步消息的标识格式:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f809936.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_24.png)
UML提供了一些顺序图的高级功能:例如可以通过顺序图实现流程的控制。具体的实现工具是通过UML提出的交互框来实现流程条件的控制。
交互框其实就是定义了流程控制图中的控制逻辑,基于交互框定义流程执行的条件。如果满足这个条件,那么则执行交互框中已定义好的顺序步骤。否则不做任何
操作。交互框中除了定义流程控制的条件外,还有一些自己特殊的操作符,具体的操作符及其作用,如下列表:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f81fe50.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_15.png)
每个关键字代表的含义都有相应的描述。大家应该都可以看明白,上述的所有含义都是针对交互框来说的。
#### 总结
如果在系统功能中有特殊需求,那么顺序图中的交互框是可以支持嵌套的。嵌套交互框的话,会提高顺序图的复杂度,降低可读性。因此我们设计时的原则尽量把复
杂的流程拆分成几个简单的,分别绘制顺序图来完成相应步骤。
#### 2、组件图。
#### 简介
众所周知,组件图是用来描述系统中的各组件之间的关系。首先我们必须知道组件的定义是什么,然后组件之间有哪些关系。理清楚这些,我们在以后的设计中才能
派上用场。UML语言对组件的定义已发生了巨大变化。在之前的版本里面,UML如下定义组件的:
UML1.1语言中对组件的描述:把某个文件或者可以运行的程序称之为组件。但是我们知道,UML出现组件图以前,组件一般用来描述COM组件或者其他的组件,因此造成冲突,所以随着后续UML语言的发布,修改了原有的含义。
UML2.x语言中对组件的的描述:组件是独立的,是运行在一个系统中的封装单位,提供了一系列的服务。
通过上述UML语言中的变迁,目前的理解是:一个系统,可以随意更换系统中的某个组建。而不会影响系统的运行。这可以理解为类似,大家熟悉IOC容器的都应该
知道,运行在IOC容器中的对象,可以看作组件,那么替换其中的提供某一服务的组件,只要满足该组件服务的相关契约就能自动完成替换。而不会影响系统的运行。
每个组件都封装了一些特殊的行为,实现了特定的服务。
组件之间的关系有哪些呢?我们通过下图来看看,组件直接可能存在的关系:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f844a02.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_25.png) 组件直接的关系基本上来说就这2种。下面会举例区别2中关系。
组件图提供的服务:组件图为系统架构师提供了解决方案的自然形式。组件图允许架构师验证系统的必需功能是由组件来完成的。组件是可以复用的。
#### 详解
组件图中包含的元素:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f857b3c.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_29.png)
下面我们分别讲解:
(1)、组件:我们知道组件是组件图中最基本的组成元素,组件上面已经讲述了组件的定义。这里就不在多介绍,组件图组成的基本单位即组件。
(2)、容器:可以为多个组件提供服务的管理容器,容器中的组件相互交互。
(3)、包:可以看作一个子系统,其实也可以看作是特殊的组件。
(4)、约束:用于定义接口规范。
(5)、给组件图中的相应元素添加相应注释信息。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f8707c2.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_39.png) 组件上可以定义自己的接口。例如上图,人这个组件提供了2个接口。Thinking与Sleep接口。
组件关系的建模:
我们来看看组件之间的关系的表示,根据上面讲解的组件的关系有依赖和泛化,参考类图中的依赖和泛化。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f88584c.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_41.png) 依赖关系,标识一个组件依赖另外一个组件,如果被依赖组件无法正常运行,那么该组件也无法运行。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f898f1c.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_43.png) 泛化关系。标识一个组件与其他多个组件的关系为继承关系。
#### 总结:
通过上面的学习我们知道:组件图主要是为系统架构师对整个系统的解决方案的自然形成,可以通过组件图的形式把系统的大体功能进行区分和设计。通过组件图把
系统功能进行抽象和分离。然后通过顺序图把功能流程细分成多个步骤,然后通过类图去构建每个流程步骤中的每个类应具有的个方法。最后形成一个完整的设计文
档。
#### 3、状态图。
#### 简介
状态图其实是针对一个对象(实体、组件其他元素等)来说的。主要是描述了,对象的行为如何改变状态的反映。我们研究UML状态图的目的就是为了搞清楚,对
象状态的变化与行为的关系。建模对象的实时行为。创建状态图的条件:当对象行为的改变与状态有关的时候才创建状态图。状态图反映了对象如何改变状态相应行为
的变化和展示对象的生命周期的创建和删除的全过程。
#### 详细
状态图可建模的对象:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f8b08c4.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_45.png)
用例:可以描述用例图中的某个用例状态的变化。
类:可以描述某个类的状态的变化。
子系统:可以描述某个子系统中状态的变化。
整个系统:类似(WF)工作流中的流程,每个节点其实就相当于一个状态。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f8cbf87.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_32.png)
上面简单的绘制了一个去餐厅吃饭的状态变化,每个状态变化的行为都有描述,当然我这里只是简单的举例说明状态图的变化,并没有详细分析的所有可能状态都画出来。
具体的状态还请大家自己练习画出来,此处只是简单的举例说明。
状态图中的元素:
状态标记:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f8dfa95.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_49.png)
状态图中可以标识一个或多个初始状态,也可以包含一个或多个结束状态。
状态图中不同状态之间的关系:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f901d9e.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_51.png) 转移关系,用来描述对象的状态从一个状态转移到另外一个状态的处理流,箭头指向转移后的状态。
状态图中提供了类似流程图中的判定的功能元素:决策点。
通过元素决策点来完成:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f91514b.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_53.png) 决策点,用来决策跳向不同的状态。
具体用例如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f928c25.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_30.png) 就是起到了一个决策的作用。这里不在复述。
状态图中的同步:
状态图中的同步主要是为了说明并发工作流的分岔和联合。下图描述了状态图中的同步条:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f93d413.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_59.png)
初始状态进入到同步条中分岔同步执行操作A与B,分别进入A状态、B状态,然后分别执行A1,B1联合进入到结束状态。
一个对象可以通过同步操作同事拥有多个状态。有时候一个对象还可以拥有不同层次的多个状态。当单个状态拥有独立的附加子状态时就可以在状态图中使用层次结
构的状态。
组合状态就是这样的比较复杂的状态结构图,有时候我们需要把一个复杂的状态细化成多个子状态的合成,那么这个复杂的状态就可以叫组合状态。
下面举例说明:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f953919.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_63.png)
组合状态B,也即复合状态B,内部可能有比较复杂的状态(C-D状态)。这种只是组合状态B中存在单个状态变化流程的情况,还可能组合状态B中包含更多的状态流。
那么我们就要用如下的状态图完成:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f96cab2.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/d76f3acf7e8c_12975/image_67.png)
上图中1代表的是下单的流程,2代表付款流程。
#### 总结
通过上面的学习我想大家对状态图有了一定的了解,那么我们来总结下,如何建模状态图。
第一步:我们知道建模状态图,首先需要抽象出来要建模的对象。
第二步:我们基于这个对象分析出该对象具有的所有状态及发生状态改变的行为。
第三步:标识每个对象状态的起始状态与结束状态。
第四步:开始创建对象的状态图,分析是否有必要创建复杂的组合状态。
系统架构设计的过程中,我们首先要分析出哪些对象需要使用状态图来描述。如果某个对象具有复杂的行为,那么可以使用活动图来建模比使用状态图更适合。每个
状态图必须至少有一个起始状态和结束状态。并且详细的分析对象发生状态改变的行为。从某个状态转移到另外一个状态的行为是什么。在某些情况下,如果对象的某
个状态无法清晰的表达时,可以通过创建组合状态来进一步细化该状态,这样能更清晰的表达对象的状态变化。
### 五、本章总结。
本章主要讲述了UML建模图形中的顺序图、状态图、组件图。并且分析了什么情况下使用各种UML建模图进行建模。并且通过简单实例说明如何使用。等UML所有的
建模图形介绍完毕后,我将针对如何我目前遇到一些问题进行分析讲解,如何遇到功能需求进行功能的分离及建模。希望大家多多提出宝贵意见。
### 六、系列进度。
1、[系统架构师-基础到企业应用架构系列之--开卷有益](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/07/1821012.html)
2、[系统架构师-基础到企业应用架构-系统建模[上篇]](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/10/1822887.html)
3、[系统架构师-基础到企业应用架构-系统建模[中篇](上)](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/11/1824084.html)
4、系统架构师-基础到企业应用架构-系统建模[中篇](下)
5、系统架构师-基础到企业应用架构-系统建模[下篇]
不断更新中(请持续关注…)
### 七、参考文献。
- [http://www.uml.org](http://www.uml.org/)--官方UML Web站点。
- [http://www.rational.com/uml/resources/documentation/index.jsp](http://www.rational.com/uml/resources/documentation/index.jsp)--提供具体UML规范的多种不同版本。
- [http://www.rational.com/rose](http://www.ibm.com/developerworks/cn/rational/r-uml/)--关于IBM Rational Rose ?这个商业UML建模工具的信息。
- [http://www.rational.com/xde](http://www.rational.com/xde)--关于IBM Rational XDE?这个与IBM的Eclipse开发平台紧密集成的商业UML建模工具的信息。
- [http://argouml.tigris.org](http://argouml.tigris.org/)--关于Argo UML这个用Java构建的开放源代码UML建模工具的信息。
- [http://uml.sourceforge.net/index.php](http://uml.sourceforge.net/index.php)--关于Umbrello UML Modeller这个用于KDE的开放源代码UMl建模工具的信息。
### 八、下篇预告。
下一篇将把本章没有讲述完毕的活动图与部署图讲解完毕,其他的不常用的建模图形可能只是简单的讲解,不会像这几篇文章那样具有说明的讲解。由于本人才疏
学浅,可能对UML建模的认识不够深入,还请各位多多支出宝贵意见,我将在后续的文章中不断的改进和学习,将自己掌握的内容写出来,一方面是帮助不熟悉UML的
朋友尽快的上手,另外也可以让自己加深印象。
';
系统建模[上篇]
最后更新于:2022-04-01 20:25:42
### 一、摘要
本文主要从系统架构中的建模开始讲解,本文讲述的内容主要是我在工作和学习过程中的总结和经验,不足之处还请大家多多批评指出,有更好的建议也可以留言
说明。本意主旨是为不熟悉系统架构建模过程和不知道如何使用建模工具,或者不熟悉如何根据需求去建立模型的角度出发,简单的阐述了在系统架构的过程中我们应
该从什么样的角度出发去分析需求并且建立抽象模型。这应该说是架构师必备的技能。
本文由浅入深,本篇将简单的介绍如何使用使用UML建模中的各个结构图与行为图,去完成抽象模型的建立。
### 二、本章内容
1、摘要。
2、本章内容。
3、建模工具介绍及使用。
4、建模中的抽象模型图。
5、本质总结。
6、系列进度。
7、下篇预告。
### 三、建模工具介绍
介绍建模工具之前,我们先来简单介绍下建模语言的定义。建模语言就是基于一系列规则、符号、图表、关键字的图形化或文本语言。建模语言的主要作用是对模
型的结构与行为进行描述。并且能够将知识和信息通过模型传递给熟悉该描述语言的人。
当今的建模语言其实并不少,其中比较有规模的如下图:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f59ecee.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_2.png)
不过最流行、最常用的当属UML建模语言(Unified Modeling Language) 统一建模语言。经过不断的发展,目前UML已成为业界公认的标准的建模语言。
我们先来了解下UML建模语言的起源:
回顾20世纪晚期--准确地说是1997年,OMG组织(Object Management Group对象管理组织)发布了统一建模语言(Unified Modeling Language,
UML)。UML的目标之一就是为开发团队提供标准通用的设计语言来开发和构建计算机应用。UML提出了一套IT专业人员期待多年的统一的标准建模符号。通过使用
UML,这些人员能够阅读和交流系统架构和设计规划--就像建筑工人多年来所使用的建筑设计图一样。
到了21世纪--准确地说是2003年,UML已经获得了业界的认同。在我所见过的专业人员的简历中,75%都声称具备UML的知识。然而,在同绝大多数求职人员面
谈之后,可以明显地看出他们并不真正了解UML。通常地,他们将UML用作一个术语,或对UML一知半解。大家对UML缺乏理解的这种状况,促进我撰写这篇关于UML
建模。当阅读完本文时,您还不具备足够的知识可以在简历上声称自己掌握了UML,但是您已具有了进一步钻研该语言的良好起点。
### 四、建模中的抽象模型
既然UML语言如此流行,本系列中也只用UML语言来进行建模,本系列中的后续章节也将基于UML建模图来完成相应的设计。
学习过UML语言的开发人员都知道UML分为以下几类模型图:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f5b66be.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_4.png)
通过上图我们知道UML的分类,分为结构型与行为型建模图形。下面的内容将详细的讲述每种建模图形的使用场景及如何使用。
#### 行为型:
我们先从行为型的建模图形来开始讲起:
#### 1、用例图:
我想用例图大家都应该基本上有所了解,只要使用过UML建模的除了基本的流程图基本上大家都会的使用外,用例图用过是最常见的一种建模图形。
用例图中主要包含的元素:系统、参与者、用例、关系。
**用例图主要的应用场景:一般用例图用来描述需求中的系统应具有的功能,系统参与者(使用者,维护者、外部系统或者用户等)与系统如何交互进行一个模**
**型话的描述。**
**用例图的目的:帮助开发团队以一种可视化的方式理解系统的功能需求。**
一般使用如下方式来进行操作:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f5d4018.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_6.png)
用来标识系统的参与者,任何与系统交互的对象,都可以叫参与者。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f5e4fc5.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_8.png)
是用来描述系统中的某个模块与参与者的一次交互过程。
系统参与者与用例之间的具体关系通过如下连线标示:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f61044b.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_10.png)
这几类不同的连线来标识不同的用例之间或者用例与参与者或者2个参与者直接直接的关系。
UML定义了3类标准的关系:
第一种:包含,通过一条直线链接2个用例,因此是用例之间的关系链接,表述了箭头的开始一端包含箭头指向的一端的用例。
例如:[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f622b90.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_44.png)
第二种:扩展,通过一个反向的直线来标识某个用例扩展了另外一个用例的行为,一般情况下箭头指向的用例即是被扩展的用例。
例如: [![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f637b29.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_48.png)
第三种:泛化,用来标识具有同质关系的参与者与参与者或者用例与用例之间的关系,泛化类似继承关系。箭头指向的为父元素。
例如:[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f64adc1.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_46.png)
除了以上的3中关系还有一种未列在规范关系的我们把它叫做关联关系。这种关系是用来描述用例与参与者直接的关系的。是通过一条直线来完成链接的,泛化关系
描述了链接的2个部分存在某种程度的交付。一般情况下,我们可以系统的功能情况分析出系统中的主动发和被动方。
如何使用用例图:
第一步:先把系统按照功能进行划分,比如一个简单的内容管理系统。先把他细化,细化成多个模块功能。每个模块的功能相对独立,但是可能又与另外一个有交
互。
第二步:把功能需求抽象,达到高内聚,低耦合的标准,然后分析出该模块功能的参与者是什么,例如用户是谁?或者细分成角色,与该模块交互还可能是数据库?
等,把所有交互的对象分析出。
第三步:把系统模块中的每个功能模块看是否能再按照子功能进行细分,细分后形成具体的用例。
第四步:分析用例与参与者之间的关系,分析同质对象(参与者与参与者、用例与用例)之间的关系。
第五步:根据以上四步完成建模。在建模的过程如果发现某块功能不清晰或者参与者不清晰,可重复前4步。
#### 2、类图:
类图也是UML建模中最常用的一种结构图,类图用来标示系统的静态结构。静态结构是由类型及关系构成。
类图表示不同的实体(人、事物和数据)如何彼此相关;换句话说,它显示了系统的静态结构。类图可用于表示逻辑类,逻辑类通常就是业务人员所谈及的事物种
类--摇滚乐队、CD、广播剧;或者贷款、住房抵押、汽车信贷以及利率。类图还可用于表示实现类,实现类就是程序员处理的实体。实现类图或许会与逻辑类图显示一
些相同的类。然而,实现类图不会使用相同的属性来描述,因为它很可能具有对诸如Vector和HashMap这种事物的引用。
类图其实就是一个长方形,内部分成3个区域。每个区域的含义不同。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f65dc8f.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_18.png)
类图中也有命名空间的概念,是通过包来实现的如果想定义该类在某个命名空间中,则在定义类名时按照如下类似格式标示
命名空间 :: 类名 [必须按照这样的形式才可以]。
类图中的有3类修饰符,每种修饰符标示的含义不同。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f66f1d0.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_20.png)
具体用法如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f681f64.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_22.png)
理解成具体的类代码的格式如下:
~~~
public class Product
{
Public string ProductName;
public void GetProductLists(string sWhere)
{
//TODO….
}
}
~~~
如果在类图中的属性定义与函数成员的定义是斜体表示的话,则表名该成员是虚成员。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f69e954.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_24.png) 虚成员
如果在类图中的属性定义与函数成员的定义是带下划线的话,则表名该成员是静态成员。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f6b2d1d.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_26.png) 静态成员
当然这是最基本的类图,还有一种特殊的,类图支持参数化类型即是.NET中的特殊类型[泛型格式]标示。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f6cadef.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_28.png) 参数化类图
具体的表示形式如:该符号在类的右上角有个长方形其中可输入类型如上图。
**类图中属性包含的元素:**
访问修饰符:Public、Protected、Private
特性/属性名称:特性/属性名称
类型:可以是自定义类型或者是系统类型。
默认值:即特性/属性的默认值,如果有的话。
重复性:可以用来定义多个对象的集合,特性值中包含的对象个数。
**类图中操作包含的元素:**
访问修饰符:Public、Protected、Private
操作名称:函数名称
操作列表:函数的参数列表。
返回值:函数的返回值,如果有的话。
函数参数列表中的参数方向:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f6e506d.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_30.png)
#### 类图之间的关联关系
首先我们知道,我们在设计类的时候就是把独立的功能放在一个类中,不同的类之间进行交互,那么我们在类图中如何去表述这样的类之间的关系呢?
类图直接的关系:
1、关联关系:关联标识2个类直接存在关系。是通过一条线来表示,关联关系中包含了2种特殊的关系:聚合和组合
聚合代表的2个类直接是has-a的关系,即部分与整体的关系,具体的图标通过一条虚线带有菱形箭头,箭头指向的方向即是整体的部分,代表该类包含另一部分。
聚合例如:[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f705314.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_32.png) 代表产品中具有ProductName这个成员。
组合举例:组合关系的标示与聚合比较类似,唯一区别实心的菱形。
组合例如:[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f715ee3.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_42.png)
组合与聚合的区别:
在聚合关系中被包含对象可能不完全依赖容器对象,也就是说ProductName不完全依赖Product。如果Product对象销毁,但是可能ProductName对象没有被销
毁。可以这么想想产品的分类不会因为产品销毁而不存在。
组合关系中则是比聚合的关联程度更高,Product完全包含ProductName。如果销毁Product时,那么ProductName也一定被销毁。产品从数据库被删除了,那
么与产品相关的的数据列属性也被删除了,这里只是举例子,可能不太合适。
#### 类图之间的泛化关系
泛化关系:存在2个类之间。一个类是另外一个类的子类,表示一个类是另外一个类的特例。
表示方法:通过一个带有空的三角形箭头的线段标识,箭头指向父类型。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f72c126.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_36.png) 表示火车和汽车是交通工具的子类型。
#### 类图之间的依赖关系
依赖关系描述为:一个类型必须依靠另外一个类才能实现相应的功能。最简单的理解方式:依赖注入中的构造函数注入。
具体的表示方法:一个带有箭头的虚线段。箭头方向标示被依赖的类型。
例如:[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f745f41.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/1fe736a8ca10_FAF2/image_38.png)
### 五、本章总结。
本章主要是对UML有个简单的介绍及详细介绍了如何构建UML图形中的用例图与类图。这是我们在建模时常用的2类图形。也是必须掌握的建模图形。
同时通过本质我们应该大脑中对UML有个新的认识,UML建模可以让我多个角度的去分析问题,然后不断的改进设计,同时能很清晰的表达功能需求功能的分离和组合
关系。本文只是简单的抛砖引玉,不足之处,在所难免,请大家批评指出。
### 六、系列进度。
1、[系统架构师-基础到企业应用架构系列之--开卷有益](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/07/1821012.html)
2、[系统架构师-基础到企业应用架构-系统建模[上篇]](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/10/1822887.html)
3、[系统架构师-基础到企业应用架构-系统建模[中篇](上)](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/11/1824084.html)
4、系统架构师-基础到企业应用架构-系统建模[中篇](下)
5、系统架构师-基础到企业应用架构-系统建模[下篇]
不断更新中(请持续关注…)
### 七、下篇预告。
下一篇中将介绍UML建模过程中其他的比较常用的UML建模图形:顺序图、组件图、状态图等。
';
开卷有益
最后更新于:2022-04-01 20:25:40
### 开篇说明
由于是自己对这些技术的学习总结和心得体会,错误之处在所难免,怀着技术交流的心态,现在发表出来,所以希望大家能够多多指点,这样能使一部分人受益同时也能纠正我的错误观点,以便和各位共同提高!
### 软件架构到底是什么
软件架构可以被简单的描述为,一系列组件之间的组合,交互,继承的关系。当然这样的解释基本上人人都可以接收。不过在我们看来,这样的说法有点过于抽象。
软件架构有这标准的定义,就是参考ANSI/IEEE的标准,软件架构可以理解为软件密集型系统中对系统的实现和部署起决定性作用的的系统。
软件架构中的关键点是应该符合项目干系人的目标,功能上当然细分成功能性的和非功能性的需求。
软件架构有一定的特殊性,架构设计必须开发的初期就确定,架构设计作为关键决策必须前期确定。
软件架构其实主要是要符合项目干系人的目标,如果无法满足项目干系人的目标,那么这个架构方案就行不通,下图是ANSI/IEEE标准中定义的系统、架构与项目干系人直接的关系。
**![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f569ac2.gif)
**
开篇中已经介绍了系统架构的表述工具有UML和Relation Rose,UML基本上已经成为国际的标准。
UML的类图:主要是描述类之间的关系。
用例图:描述使用场景。
组件图:用来描述系统中的可重用部分。并且容易看出组件与二进制文件之间的对应关系。
通过UML工具,我们能够更深层次对系统架构进行不同角度的描述。抓住其核心。
软件架构的验证,目前没有什么好的办法可以自动验证软件架构是否可以达到项目干系人的目标,只有通过多种方式多个级别的测试。
例如通过单元测试,来验证单一的功能,集成测试来评估系统的兼容性,验收测试来验证用户的满意度,程序是否提供必要的功能。
除了UML建模工具之外,还有IBM比较著名的Relation Rose,这里大概介绍下该工具具有的视图模式:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f57d32c.gif)
### 系统的架构
可以这样说,软件系统的架构过程中没有什么系统是不可拆分的,系统的开发方法越敏捷,为开发人员实现架构是预留的空间越大。
系统架构师将系统分解的过程,其实最终形成的就是一份为开发人员提供的详细设计说明书。当然详细设计说明书的内容和格式也取决于开发方法。
### 架构是什么
架构大多体现在难以改变或者改变起来代价较大的决定上。但是最终还是需要有人做决定。
系统分析师分析系统做什么,架构师设计如何去做。
架构师是需求与详细说明的纽带。
架构师的职责:架构师应该参与到开发的全过程当中。包括分析需求与架构设计、实现、测试、继承与部署。
按照ISO的定义架构师的定义如下:负责系统架构的人、团队或组织。
微软则对系统架构是做了如下的划分:
1、企业架构师。
2、基础架构师。
3、特定技术架构师。
4、解决方案架构师。
### 最后总结软件开发过程中的一些法则:
1、为了一个赶不上进度的项目增加人手,只会让项目更加落后于进度。
2、程序的复杂性会一直的增加,直到维护人员感觉到力不从心为止。
3、建筑师与开发人员写程序不同,如果建筑师按照开发人员的方式开建造,只会成为历史中的败笔。
### 下一篇文章内容预告
UML的架构设计
如何通过UML工具来进行建模,通过不同角度的分析,得出核心的设计。
';
设计模式-系列索引
最后更新于:2022-04-01 20:25:38
园子里面有太多优秀的设计模式文章了,但是可能每个人的出发角度和关注点不同,可能会对每个模式理解的角度和切面不同,我想以我自己理解的方式来跟大家共同探讨下常用的设计模式,并且我会结合
工作中的开发实际场景来说明每个模式的用法和特点,希望能对大家有所帮助,当然这些内容都是个人在实际项目中的总结和实践,错误或者理解有误之处,还请大家多多指正,多谢大家前来交流!
创建型
1、[设计模式系列-单件模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/02/1841390.html)
2、[设计模式系列-工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/11/30/1892227.html#1973367)
3、设计模式系列[-抽象工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/01/1893388.html)
4、设计模式系列[-创建者模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/02/1894771.html)
5、设计模式系列[-原型模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/04/1896471.html)
结构型
1、[设计模式系列-组合模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/06/1898161.html#commentform)
2、[设计模式系列-外观模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/06/1897398.html)
3、[设计模式系列-适配器模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/09/1901040.html)
4、[设计模式系列-桥模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/10/1902185.html)
5、[设计模式系列-装饰模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/11/1903392.html)
6、[设计模式系列-享元模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/12/1903728.html)
7、[设计模式系列-代理模式](http://www.cnblogs.com/hegezhou_hot/archive/2011/02/20/1958965.html)
行为型
1、[设计模式系列-命令模式](http://www.cnblogs.com/hegezhou_hot/archive/2011/02/26/1965769.html)
2、设计模式系列-观察者模式
3、设计模式系列-策略模式
4、设计模式系列-职责模式
5、设计模式系列-模板模式
6、设计模式系列-中介者模式
7、设计模式系列-解释器模式
希望[何戈洲](http://blog.csdn.net/hegezhou/article/list)的这个系列能够给您帮助,我会全力写好,谢谢!
';
系列索引
最后更新于:2022-04-01 20:25:36
### 系统架构师-基础到企业应用架构-索引
系统架构师-基础到企业应用架构系列会从,系统架构的起源、发展、架构师必备的基础知识与技能、如何把架构应用到企业应用中去。整个系列计划30篇左右,每
一篇都是自己在系统架构过程中的总结和经验,每一篇我都会抱着认真的态度去完成,宁缺毋滥的原则。希望本系列看完之后不但能够帮助看过这个系列的人对系统架
构有深刻的认识,并且能够掌握系统架构中的必备知识,应用到自己的工作中去,更可以共同提高大家的个人能力。本系列希望能够抛砖引玉,希望大家能够多提出宝
贵意见。
#### 前篇
1、[系统架构师-基础到企业应用架构系列之--开卷有益](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/07/1821012.html)
2、[系统架构师-基础到企业应用架构-系统建模[上篇]](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/10/1822887.html)
3、[系统架构师-基础到企业应用架构-系统建模[中篇](上)](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/11/1824084.html)
4、[系统架构师-基础到企业应用架构-系统建模[中篇](下)](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/14/1826314.html)
5、[系统架构师-基础到企业应用架构-系统建模[下篇]](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/16/1828169.html)
6、[系统架构师-基础到企业应用架构-系统设计规范与原则[上篇]](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/18/1830306.html)
7、[系统架构师-基础到企业应用架构-系统设计规范与原则[下篇]](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/23/1833393.html)
8、系统架构师-基础到企业应用架构-设计模式[上篇]
9、系统架构师-基础到企业应用架构-设计模式[中篇]
10、系统架构师-基础到企业应用架构-设计模式[下篇]
#### 中篇
11、[系统架构师-基础到企业应用架构-企业应用架构](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/17/1853909.html)
12、系统架构师-基础到企业应用架构-分层[上篇]
13、系统架构师-基础到企业应用架构-分层[中篇]
14、系统架构师-基础到企业应用架构-分层[下篇]
15、[系统架构师-基础到企业应用架构-表现层](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/12/1849313.html)
16、[系统架构师-基础到企业应用架构-服务层](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/03/1841756.html)
17、[系统架构师-基础到企业应用架构-业务逻辑层](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/01/1840642.html)
18、[系统架构师-基础到企业应用架构-数据访问层](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/08/1846200.html)
19、系统架构师-基础到企业应用架构-组件服务
20、系统架构师-基础到企业应用架构-安全机制
#### 后篇
21、单机应用、客户端/服务器、多服务、企业数据总线全解析
22、系统架构师-基础到企业应用架构-单机应用(实例及demo)
23、系统架构师-基础到企业应用架构-客户端/服务器(实例及demo)
24、系统架构师-基础到企业应用架构-多服务(实例及demo)
25、系统架构师-基础到企业应用架构-企业数据总线(实例及demo)
26、系统架构师-基础到企业应用架构-性能优化(架构瓶颈)
27、系统架构师-基础到企业应用架构-完整的架构方案实例[上篇]
28、系统架构师-基础到企业应用架构-完整的架构方案实例[中篇]
29、系统架构师-基础到企业应用架构-完整的架构方案实例[下篇]
30、系统架构师-基础到企业应用架构-总结及后续
最后[何戈洲](http://blog.csdn.net/hegezhou) 会尽心尽力写好这个系列,同时由于是自己对这些技术的使用总结和心得体会,错误之处在所难免,怀着技术交流的心态,在[C](http://blog.csdn.net/hegezhou)[SDN](http://blog.csdn.net/hegezhou)上发表出来,所
以希望大家能够多多指点,这样在使一部分人受益的同时也能纠正我的错误观点,以便和各位共同提高,后续文章敬请关注!
';
设计模式系列-命令模式
最后更新于:2022-04-01 20:25:33
### 一、开篇
上一篇我们讲述了结构型模式中的代理模式。本篇,我们将会开始讲述行为型模式中的命令模式,在设计模式的这些基本的模式完成后,我将会将一些经常用的其他的一些扩展的模式进行讲解,希望能够引起大家的共鸣。
我们先来看看命令模式的定义吧:
命令模式是将一类对象的功能操作进行抽象,一般来说,这些对象有相同的方法,所以这类对象有着类似的操作,我们通过抽象,就可以定义出一个命令对象,通过这样的方式,用户程序在使用的时候,只与该命令对象打交道,而不用与一类对象打交道,降低了耦合性,提高了程序设计的灵活性。
命令模式适应于一组对象他们的操作形式非常的类似,这个时候我们可以把对象的行为进行抽象,抽象成命令对象,实现解耦,下面来举例说明:
例如我这里要实现多数据的保存操作,例如支持SQLServer与Oracle数据库,还有Access数据库,那么假设我这里定义相关的CRUD方法如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b6afc25.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261526529321.png)
对于上述的方法,可能我们为每个数据库定义了自己的相应的数据库操作命令方法,例如我们都定义为Create方法,Update方法,Delete方法,
Retrieve方法(查询数据)。
那么我们可以抽象出一个公共的命令对象,定义这样的命令抽象对象:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b6cee65.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261526585662.png)
本篇以此为题目展开,来讲述命令模式的完整实现,可能功能还不是很完善,但是希望大家能够看出命令模式解决的问题及解决问题的思路,如果我某个地方表述有误或者说表达的不清楚,请大家指出批评,并谢谢大家的意见和建议。
### 二、摘要
本篇将以多数据访问支持来题目来讲述命令模式的用法,可能部分功能没有讲到或者提到,还请大家补充,由于本文都是个人对命令模式的理解,可能部分观点还存在理解上的偏差,或者不深入,还请大家批评指出。
本文将从下面的几个内容展开说明:
1、命令模式的使用场景
2、命令模式的经典实现。
3、命令模式的其他应用。
4、总结命令模式。
我们看看经典的命令模式的类图吧,对比下经典命令模式的,我们下面给出命令模式的其他应用场景。
[![cf59c6de57f78257ccbf1ab1](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b6e4a42.jpg "cf59c6de57f78257ccbf1ab1")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261527054130.jpg)
### 三、本文大纲
a、开篇。
b、摘要。
c、本文大纲。
d、命令模式的特点及使用场景。
e、命令模式的其他方案。
f、命令模式使用总结。
g、系列进度。
h、下篇预告。
### 四、命令模式的特点及使用场景
我们来分析下命令模式的使用场景吧,一般情况下如下几类场景中使用命令模式会达到很好的效果:
1、当一个应用程序调用者与多个目标对象之间存在调用关系时,并且目标对象之间的操作很类似的时候。
2、例如当一个目标对象内部的方法调用太复杂,或者内部的方法需要协作才能完成对象的某个特点操作时。
3、有时候调用者调用目标对象后,需要回调一些方法。
对于上图中的静态对象,我们来进行解释下,并且我们必须深入理解这几个对象的含义。
Invoker:调用者对象。
Receiver:接收调用者请求执行操作的目标对象。
ICommand:用于解耦目标对象与调用者之间的抽象命令对象。
下面我们来分析下上面讲述的CRUD的经典命令模式的实现:
1、定义SQLServer的CRUD的简单实现示例代码:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b704ae3.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/20110226152709113.png)
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b72a670.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261527218235.png)
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b742f0f.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261527317702.png)
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b766206.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261527464198.png)
这里补上DO方法:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b78d479.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102270842345198.png)
2、CRUD的ICommand接口定义:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b7aa087.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261527525490.png)
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b7bfb29.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261527585103.png)
我们这里定义的Receiver定义成枚举类型的对象,来枚举SQLserver执行的具体的操作。
3、下面给出命令对象的基本实现:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b7dcad2.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261528065706.png)
4、具体的命令对象的实现:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b80136a.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261528143702.png)
5、调用者代码
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b816df1.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261528369090.png)
6、测试代码:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b835358.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261528541701.png)
通过上面我们给出了命令模式的一个经典的实现方案。下面我们来看看其他的解决方案。在实际的项目中,可能我们很少会设置上面的Receiver对象的,也很少把他作为command的一个属性放在接口中。我们更习惯将Receiver对象作为ICommand中通用接口方法的一个变量传入给目标对象。当然不同的场景决定了不同的模式用法。通过经典的方案,我们能够看出命令模式的用法。
### 五、命令模式的其他实现方案
一、轻量级的事件队列
考虑如下场景,如果我们可能在某个调用者在执行一个动作时,我们不想调用者了解那么多的细节和内部的交互,并且调用者的这个方法调用了很多目标对象的不同方法,来协作完成一些操作。这些目标对象的方法要么顺序有限制,要么无顺序的限制等。
1、创建3个类,每个类都有自身的成员方法输出一段字符串
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b84ca8f.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261529027221.png)
2、定义一个委托
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b862365.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261529261921.png)
3、定义调用者
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f473c68.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261529387602.png)
4、测试代码
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f4978a7.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261532385659.png)
5、输出结果:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f4b009d.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261532527794.png)
二、异步命令
考虑现实我们在开发的过程中经常会遇到这样的场景吧:我们需要执行一个时间特别长的任务,如果我们将这个长任务与其他的任务一起采用同步执行的方式,客户的体验不好,例如我们在下载的时候,如果我们能做到异步的方式的话,后台执行文件下载的操作,前台用户可以继续执行其他的操作,而不是等待下载完毕,才能继续操作。这个时候,我们可能通过异步命令的方式来操作,效果肯定会更好。不然也不会出现那么多的异步编程的思想了。
下面我们通过命令模式来实现异步命令模式:
1、 定义命令抽象接口
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f4c9676.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261533007492.png)
2、定义异步命令接口
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f4ddeb4.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261533152037.png)
3、异步命令抽象的实现
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f50699d.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261533215313.png)
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f525911.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261533283441.png)
上面给出了异步的调用方式,通过上面的这样的代码形式,就能完成异步的访问
4、实体的内容
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f536a06.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102261533343370.png)
上面实体的内容可以改进成为,通过统一添加的方式来注册事件
具体的调用方式如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996f550527.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102270842371488.png)
### 六、命令模式使用总结
通过上面的讲解我想大家应该对命令模式有了一定的了解,命令模式就是将一组对象的相似行为,进行了抽象,将调用者与被调用者之间进行解耦,提高了应用的灵活性。命令模式将调用的目标对象的一些异构性给封装起来,通过统一的方式来为调用者提供服务。
相信大家通过实战能够体会该模式的好处。
### 七、系列进度
创建型
1、[设计模式系列-单件模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/02/1841390.html)
2、[设计模式系列-工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/11/30/1892227.html#1973367)
3、设计模式系列[-抽象工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/01/1893388.html)
4、设计模式系列[-创建者模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/02/1894771.html)
5、设计模式系列[-原型模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/04/1896471.html)
结构型
1、[设计模式系列-组合模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/06/1898161.html#commentform)
2、[设计模式系列-外观模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/06/1897398.html)
3、[设计模式系列-适配器模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/09/1901040.html)
4、[设计模式系列-桥模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/10/1902185.html)
5、[设计模式系列-装饰模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/11/1903392.html)
6、[设计模式系列-享元模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/12/1903728.html)
7、[设计模式系列-代理模式](http://www.cnblogs.com/hegezhou_hot/archive/2011/02/20/1958965.html)
行为型
1、设计模式系列-命令模式
2、设计模式系列-观察者模式
3、设计模式系列-策略模式
4、设计模式系列-职责模式
5、设计模式系列-模板模式
6、设计模式系列-中介者模式
7、设计模式系列-解释器模式
### 八、下篇预告
下一篇我将会讲解设计模式中的经典模式,观察者模式,该模式是委托应用的经典代表,不熟悉委托的话,可能就会很好理解该模式。希望大家提出宝贵意见,我将会不断的改进写作的水平,希望与大家共同交流和进步。
';
设计模式-代理模式
最后更新于:2022-04-01 20:25:31
### 一、上篇回顾
很久没有更新设计模式系列的文章了,有了很多热心朋友的反馈,我决定继续将这个系列赶快写完,最近由于过年了,有很多相关的事宜要做,所以没有时间来写,也是对大家的说下抱歉,感觉写文章的时间越来越少了,不过我会努力,尽快将这个系列写完,与大家共勉,希望大家有什么意见或建议,都可以帮我提出来,我好改进,谢谢!。
本文主要是讲述设计模式中的结构性模式中的最后一个本系列讲述的模式,也是经常用到的模式,代理模式,由于目前我们在很多的技术中都会用到
这个代理模式,所以对我们来说,代理模式是必须掌握的模式之一。我们先来看看代理的思路及原理:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b3ed742.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201353379425.png)
通过上面的图片,我们可以看到,通过增加代理来解耦A与C之间的调用,这样可以封装原来C调用A的一些相关细节,转换成C直接调用B中封装后
的代理方法,则等同于访问A。对于WebService的远程调用时,如果我们使用添加Web引用的方式,那么WebService会为我们自动生成代理类的,这个我这里就不演示了,包括Castle中的AOP等实现方案都是基于动态代理的机制来实现,当然思路都是这样的,WCF中也有用到代理的思想。
### 二、摘要
前面我们讲述了外观模式中的关于动态代理中的一些实现,当然代理模式与外观模式的侧重点还是有所不同,外观模式是将众多细粒度的功能,封
装成一个粗粒度的功能,供客户应用程序使用。而代理模式,为其他对象提供一个代理类,通过该代理类来完成目标对象的访问,代理模式相对外观模式来说,关键不同是在内部,外观我们知道是将细粒度的功能进行简单封装,而代理模式则是内部实现很复杂,其复杂性主要体现在来自如下的几类复杂性:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b420bbf.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201353489906.png)
可能上述的复杂性还不完整,例如还可能有目前的比较新兴的大数据量的虚拟代理或者是智能代理,这方面由于自身不足,所以还无法讲述。
本文将会结合举例说明上述的几类代理的复杂性的简单说明,希望能说明清楚。
### 三、本文大纲
a、上篇回顾。
b、摘要。
c、本文大纲。
d、代理模式的特点及使用场景。
e、代理模式的经典实现。
f、代理模式的其他方案。
g、代理模式使用总结。
h、系列进度。
i、下篇预告。
### 四、代理模式的特点及使用场景
我们先来看看代理模式的特点及使用场景吧,我们先来看看一个简单的场景吧:
我们现在要构建一个分布式应用程序,那么一般在.NET平台下,我们一般会采用WCF或者WebService的方式来发布应用,不管是平时大家听说的SOA架构的实现,还是其他的ESB总线架构等,也无非是二种实现方式,一种是通过API接口编程来实现,通过WCF的Remoting或者是其他的方式来调用远程服务,另一种是通过WebService的形式来发布服务,那么既然有了发布服务之后,那么我们之后的操作可能更多关心的是,如果在客户端使用
这个服务,那么一般我们可能采用的最常用的方式,就是在客户端由平台自动生成一个代理或者我们自己写一个代理类,当然这个代理类可以是通用的代理类或者是为某些服务单独写代理,能够更方便的使用及提升效率等。
通过上面的说明,那么我们现在基本上知道了,代理模式的作用体现在哪里,下面我们来详细展开说明吧;当我们的一个服务写的很复杂,但是我们在客户端调用的时候,我们又不希望在客户端使用起来太复杂,这个时候,可能我们想我们通过使用代理类,那么通过代理类,这个客户端与远程的服务类进行交互过程就变成客户端与代理类的交互,那么给客户的感觉就像服务类就在本地一样,这样不但降低了复杂性,而且也降低了耦合性。
那么一般代理类有什么要求呢?一般来说代理对象必须实现目标对象定义的一些接口,只有这样,客户端应用程序在使用的时候,通过接口调用来访问目标对象的服务,否则就等于引入复杂度,反而没有解决问题。
使用代理的目的是控制客户端程序访问目标对象,因此代理必须知道目标对象的类型及目标对象在哪里,如何访问等都必须明确。
代理对象有的时候也可以是抽象类型,这样目标类型就可以是未确定的,我们可以通过创建型模式来动态的创建目标对象,当然前提是这些目标对象是代理对象类型。
代理模式的类图
![](image/56a5c105910ac.jpg)
### 五、代理模式的经典实现
下面给出代理模式的经典实现:
我们以如下场景为例,我们现在要实现一个MP3播放的相关功能,一般来说有很多的音频文件;
下面我们来看看如何使用代理模式来实现。
(1)、定义客户端调用的具体的音乐媒体类型类型
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b439805.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201353507723.png)
(2)、定义客户端调用的目标对象的接口
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b44ec0d.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201353523904.png)
(3)、定义具体的目标类型的实现
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b461665.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201353572329.png)
(4)、定义代理类,该代理类实现了目标类型的接口。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b47b95c.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354023437.png)
(5)、具体的客户端调用
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b491a9a.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354042093.png)
上面基本上给出了一个简单的例子说明,当然具体的代理模式的思路就是这样了,当然参考上面的类图来做的话,和我的这个形式差不多,具体的
思想就是为目标类型定义一个接口,然后代理类实现该接口,那么在代理类中指定具体的目标类型的调用,完成目标类型的调用,返回调用后的结果,那么就等于代理类封装了目标类型的调用。
### 六、代理模式的其他实现方案
上面我们给出了代理模式的经典实现方案,那么我们本节看看其他的实现方案,来扩展下我们的方案的使用场景及一些其他的应用场景的情况:
我们给出WebService的示例过程吧:
(1)、 为了说明我们给出的示例过程,我们来新建一个ASP.NET WEB应用程序网站,添加一个WebService服务文件。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b4aabc6.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354114431.png)
(2)、 选择添加一个WebService文件
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b4cc285.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/2011022013541565.png)
(3)、添加完后,修改HelloWord方法,添加一个name字段,代表输入字符串,输出相应的代码
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b4e38ed.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354183115.png)
(4)、添加完毕后,在浏览器中查看
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b50f158.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354241125.png)
(5)、测试,是否服务正确。运行后的结果应该如下:
[ ![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b5446a3.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354306005.png)
置于其他的相应的信息我就补贴出来了,然后我们将webservice服务发布出来,通过二种形式来添加代理
1、通过web引用的形式:
(1)、先找到webservice服务的发布地址
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b5636c0.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354378343.png)
(2)、复制地址,并且在要引用该webservice服务的项目中在引用文件夹中点击右键
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b580c13.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354415339.png)
(3)、将复制的地址,输入到服务引用的地址栏中
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b59729e.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354465683.png)
(4)、点击前往,系统就会自动与webservice建立测试连接。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b5b0338.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201354539691.png)
如果没有出现上述的服务内容,那么则可能服务没有发布,或者服务的引用添加的路径不对等。点击确定,这个时候,我们来看看代理文件生成的内容:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b5cf7d9.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355073188.png)
我们来看看系统为我们自动生成的WEB服务代理的代码吧:
通过reflactor中的对象浏览器来查看系统生成的内容吧:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b5eab4d.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355116696.png)
具体的代码太多了,我这里就不贴出了,大家可以看看,我这里给出解析webservice的一些通用的统一代理代码。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b615596.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355165578.png)
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b630075.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355207624.png)
这样就完成通用的Get请求的方式来调用webservice服务。
### 七、代理模式使用总结
通过上面的webservice的讲述,我想大家对代理模式还是会有些陌生,其实代理模式我们前面也说道,代理是将目标对象的复杂性进行封装,通过代理来完成调用,那么我们针对前面的客户端调用的目标类型的接口定义,并且目标对象要实现这个接口,代理类也要实现这个接口。
下面来总结下代理模式与外观模式的区别:
1、外观模式也是屏蔽复杂性的,但是外观模式不会实现客户端调用的目标类型接口。
2、一般客户端调用外观模式的方法都是直接调用。
3、代理模式中对客户端目标对象类型抽象接口具体化了。
4、外观模式是代理模式中一种特殊的子级模式(广泛的,非约束性)。
针对前面我们提到过,代理模式中还有将代理类定义成抽象类型,然后完成动态的调用的情况,那么我们看看我们如何来组织呢?
1、定义多个播放文件格式对象
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b64e1f0.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355248930.png)
新增加上述的3个文件
2、修改playProxy的代码如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b6658be.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355285370.png)
3、具体的代理代码如下:这里参考AOP的实现机制
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b68568e.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355331004.png)
4、具体的调用代码如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b696934.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/201102/201102201355348331.png)
当然这里的具体的调用过程还有很多方法可以进行改进的更好,比如在内部的枚举模式,修改成创建工厂的形式来完成对象的动态创建及调用等。我这里就
不进行优化了,只是展示出思路和方案,希望大家提出不同的意见!
### 八、系列进度
创建型
1、[系统架构技能之设计模式-单件模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/02/1841390.html)
2、[系统架构技能之设计模式-工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/11/30/1892227.html)
3、[系统架构技能之设计模式-抽象工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/01/1893388.html)
4、[系统架构技能之设计模式-创建者模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/02/1894771.html)
5、[系统架构技能之设计模式-原型模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/04/1896471.html)
结构型
1、[系统架构技能之设计模式-组合模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/06/1898161.html#commentform)
2、[系统架构技能之设计模式-外观模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/06/1897398.html)
3、[系统架构技能之设计模式-适配器模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/09/1901040.html)
4、[系统架构技能之设计模式-桥模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/10/1902185.html)
5、[系统架构技能之设计模式-装饰模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/11/1903392.html)
6、[系统架构技能之设计模式-享元模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/12/1903728.html)
7、系统架构技能之设计模式-代理模式
行为型
1、系统架构技能之设计模式-命令模式
2、系统架构技能之设计模式-观察者模式
3、系统架构技能之设计模式-策略模式
4、系统架构技能之设计模式-职责模式
5、系统架构技能之设计模式-模板模式
6、系统架构技能之设计模式-中介者模式
7、系统架构技能之设计模式-解释器模式
### 九、下篇预告
下一篇我们将开始讲述行为型模式中的“命令模式”该模式是比较常用的模式,也是大众化的模式,希望能给大家说明清楚,对我自身来说也是一个不小的挑战,欢迎大家拍砖。
';
设计模式系列-原型模式
最后更新于:2022-04-01 20:25:29
### 一、上篇回顾
上篇创建者模式中,我们主要讲述了创建者的几类实现方案,和创建者模式的应用的场景和特点,创建者模式适合创建复杂的对象,并且这些对象的每个组成部分的详细创建步骤可以是动态的变化的,但是每个对象的组装的过程来说可能是相对固定的或者说是对象的创建的过程是固定的,那么通过创建者模式可以很好的解决这类复杂对象的创建,而在我们的生活中或者是项目中可能会有这个方面的需求,那么使用创建者模式无疑是好的选择。
创建者模式中的每个对象组成部分的构建都是对象本身提供的内部方法,具体的创建者只是调用要创建的对象的内部的相应组成部分的构建方法,组织这些对象内部构建方法的执行顺序,完成对象的完整构建。当我们的客户应用程序需要调用这个创建者时,我们只需要通过指导者调用的形式,提供统一的创建者访问入口,通过构造函数注入或者配置文件的形式来完成创建者的注入。
### 二、摘要
本文主要是讲述创建型模式中一个比较特殊的模式-原型模式,这个模式呢,有个最大的特点是克隆一个现有的对象,这个克隆的结果有2种,一种是是浅复制,另一种是深复制,这里我们也会探讨下深复制和浅复制的原理,这样可能更方便大家理解这个原型模式的使用。我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象而不需要提供专门的new()操作就可以快速完成对象的创建,这无疑是一种非常有效的方式,快速的创建一个新的对象。本文将会从以下几个方面进行讲述:
1、原型模式的使用场景和特点
2、浅复制和深复制的原理。
3、举例说明浅复制和深复制。
4、原型模式的实现方案。
5、总结原型模式。
我们这里先给出一个原型模式的原理图:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b32547d.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/3711c6dafbd3_12FBE/image_2.png)
### 三、本文大纲
a、上篇回顾。
b、摘要。
c、本文大纲。
d、原型模式的特点及使用场景。
e、深复制和浅复制。
f、原型模式的实现方案。
g、原型模式使用总结。
h、系列进度。
i、下篇预告。
### 四、原型模式的特点及使用场景
原型模式的主要思想是基于现有的对象克隆一个新的对象出来,一般是有对象的内部提供克隆的方法,通过该方法返回一个对象的副本,这种创建对象的方式,相比我们之前说的几类创建型模式还是有区别的,之前的讲述的工厂模式与抽象工厂都是通过工厂封装具体的new操作的过程,返回一个新的对象,有的时候我们通过这样的创建工厂创建对象不值得,特别是以下的几个场景的时候,可能使用原型模式更简单也效率更高。
1、如果说我们的对象类型不是刚开始就能确定,而是这个类型是在运行期确定的话,那么我们通过这个类型的对象克隆出一个新的类型更容易。这个怎么理解。例如我们有的时候在处理DataTable中的记录进行筛选后,放在一个新的DataTable 中,我们知道如果说2个dataTable的架构不同,那么必须手动的显示的赋值,否则无法使用如下方式进行导入数据:
下面给出测试的相关代码和说明
~~~
public class DataTableDemo
{
public void CloneTest()
{
string cmdText = "SELECT * FROM TABLE";
DataTable dt = new DataTable();
//通过执行上面的cmdText 返回一个dataTable对象;
//这时候我们可以如下形式复制一个新的dataTable,而不用先创建一个dataTable,然后把每一列都显示的循环添加到新的dataTable中,
//这是很大的工作量。
DataTable dt1 = dt.Clone();
//克隆一个新的对象 dt1.
#region 不采用克隆的形式复制一个新的dataTable
DataTable dt2 = new DataTable();
foreach (DataColumn column in dt.Columns)
{
dt2.Columns.Add(column.ColumnName);
}
#endregion
}
}
~~~
2、有的时候我们可能在实际的项目中需要一个对象在某个状态下的副本,这个前提很重要,这点怎么理解呢,例如有的时候我们需要对比一个对象经过处理后的状态和处理前的状态是否发生过改变,可能我们就需要在执行某段处理之前,克隆这个对象此时状态的副本,然后等执行后的状态进行相应的对比,这样的应用在项目中也是经常会出现的。
假设我们有这样的需求,我们在ORM框架的设计中,经常会遇到这样的问题,我们在处理某个对象的编辑状态的时候,我们想框架给我们生成的更新数据库的SQL语句,不包含数据列没有发生变化的列,不要出现在更新语句中,这个时候,可能一个方案会是,编辑前克隆一个对象,然后等编辑后提交的时候,生成相应的语句时进行对比之前克隆的对象,看看是否数据发生变化,如果说对象的部分数据列发生变化,那么就只是把变化的数据列进行更新。
当然上面我只是给出了一种比较简单的,但是效率不是很高的实现方案,还有很多好的方案我就不讨论了,这里只是为了说明原型模式的可用场景。
如果对上面的方式不是很理解或者看文字比较累的话,可以看下面的图,应该就比较清晰了。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b341cfe.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/3711c6dafbd3_12FBE/image_4.png) 这就是这种情况下可能原型模式有比较好的表现。
3、当我们在处理一些对象比较简单,并且对象之间的区别很小,可能只是很固定的几个属性不同的时候,可能我们使用原型模式更合适,例如我们生活中的彩虹的七彩的颜色,等等,我们只需要根据现有的一个颜色对象,克隆一个新的颜色对象,然后修改具体的颜色的值就可以满足要求,然后如果通过我们之前讲述的创建型工厂,抽象工厂模式等相对来说就引入新的依赖,并且复杂度也有所提高。例如我们的生活中的颜色的克隆:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b3711d3.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/3711c6dafbd3_12FBE/image_6.png) 我们都可以通过红色来克隆其他的所有颜色,只是修改相应的个别属性即可,远比创建一个新的对象,然后给对象的各个属性赋值来的简单和方便,当然有的时候,如果我们并不需要基于现有的对象复制新的对象,或者我们需要的就是一个干净的空对象,那么我的首先还是工厂模式或者抽象工厂模式啦。
### 五、深复制和浅复制
既然我们本篇讲述了原型模式的具体应用,那么我们就必须先搞清楚深复制和浅复制,否则也没有办清楚原型模式中的具体的克隆过程和克隆出来的对象的详细情况。
~~~
.NET Freamwork 内置的每个继承自System.Object都有保护成员方法:
//
// 摘要:
// 创建当前 System.Object 的浅表副本。
//
// 返回结果:
// 当前 System.Object 的浅表副本。
[SecuritySafeCritical]
protected object MemberwiseClone();
~~~
系统为我们内置提供了复制对象本身的方法,不过这个方法返回的是一个浅复制的对象副本,而且.NET给我提供了一个System.ICloneable的接口,
我们通过实现这个接口,可以为对象提供自定义的克隆方法。
为了搞明白浅复制和深复制,那么我先要搞懂这2者的区别,.NET本身提供了浅复制的方法,而深复制的方法需要自己实现接口来完成。
我们先来看看浅复制后的对象和对象副本的情况:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b39726b.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/3711c6dafbd3_12FBE/image_8.png)
我们再看看看深复制的对象和对象副本的情况:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b3b7382.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/3711c6dafbd3_12FBE/image_12.png) 通过上面的描述,大家应该针对浅复制和深复制的区别有了大概的了解,那么我们再结合程序代码来分析吧,可能大家会更熟悉具体的应用。我们先来看看最简单的浅复制和深复制情况,我们这里举例来说吧:
我们定义一个杯子类,并且简单定义杯子的几项简单的属性,具体代码如下:
~~~
///
/// 杯子类
///
public class Cup : ICloneable
{
private double _rl;
private int _height;
private Factory _factory;
///
/// 高度
///
public int Height
{
get
{
return _height;
}
set
{
_height = value;
}
}
///
/// 容量
///
public double RL
{
get
{
return _rl;
}
set
{
_rl = value;
}
}
///
/// 生产厂家
///
public Factory Factory
{
get
{
return _factory;
}
set
{
_factory = value;
}
}
#region ICloneable 成员
public object Clone()
{
return this.MemberwiseClone();
}
#endregion
}
~~~
具体的测试代码:
~~~
class Program
{
static void Main(string[] args)
{
Cup cup = new Cup();
cup.Height = 2;
Cup cup1 = (Cup)cup.Clone();
cup1.Height = 1;
Console.WriteLine(cup.Height == cup1.Height);
System.Threading.Thread.Sleep(10000);
}
}
~~~
运行结果如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b3d2b60.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/3711c6dafbd3_12FBE/image_14.png)
综上所述,我们知道,对于值类型的成员,浅复制也是在副本中重新创建的成员,对应到内存的栈上,分配新的内存空间。那么对于引用类型则因为浅复制的时候,对象和对象副本共用同一个引用对象,那么不管是在对象还是对象副本中修改了相应的引用成员了之后,那么这个引用类型的成员就会发生变化。
因为2个对象指向同一个内存地址,那么任何一个修改操作都会产生改变。
那么对于上面的这个类如何修改这个类的实现才能实现深复制呢?
将上面的Clone方法如下实现:
~~~
public object Clone()
{
Cup cup = (Cup)this.MemberwiseClone();
Factory factory1 = new Factory();
factory1.FactoryName = this.Factory.FactoryName;
cup.Factory = factory1;
return cup;
}
这样就完成了对象的深复制,不管是值类型的成员还是引用类型的成员,这样的对象和对象副本,对任何一个成员属性的修改,都不会影响到改变对象的值。
### 六、原型模式的实现方案
#### 6.1 原型模式的经典实现
我们先来看看原型模式的经典实现,我们这里已颜色为例来说名下经典实现吧
定义一个接口, 用来表述所有的颜色对象接口:
~~~
public interface IColorDemo
{
IColorDemo Clone();
int Red
{
get;
set;
}
int Green
{
get;
set;
}
int Blue
{
get;
set;
}
}
~~~
我们这里给出红色的具体实现代码:
~~~
public class RedColor : IColorDemo
{
private int red;
private int green;
private int blue;
public int Red
{
get
{
return this.red;
}
set
{
this.red = value;
}
}
public int Green
{
get
{
return this.green;
}
set
{
this.green = value;
}
}
public int Blue
{
get
{
return this.blue;
}
set
{
this.blue = value;
}
}
#region IColorDemo 成员
public IColorDemo Clone()
{
return (IColorDemo)this.MemberwiseClone();
}
#endregion
}
~~~
因为上面的对于颜色,都是通过RGB不同的比例配置出来的,所以我就定义了3个整形的变量,所以我这里只是演示说明。那么具体的测试代码如下:
~~~
static void Main(string[] args)
{
IColorDemo color = new RedColor();
color.Red = 255;
IColorDemo color1 = color.Clone();
color1.Blue = 255;
Console.WriteLine(color.Blue == color1.Blue);
System.Threading.Thread.Sleep(10000);
}
~~~
返回的结果为false。代表对象副本的修改不会影响对象本身的状态。
#### 6.2、原型模式的其他情况
上面讲述了简单的浅复制的情况,那么我们来分析下深复制原型的实现吧,深复制可能考虑的情况相对来说就会比较复杂,因为有可能对象是之间
有继承关系或者引用关系的时候,可能我们深复制的时候就需要注意,当然这对我们也是个考验。一般来说深复制一方面可以采用上面我给出的那种简单的深复制对象的时候的方案,还可以通过序列化的形式来进行对象的复制。下面我们来通过序列化的形式来实现原型模式吧:
我们先给出序列化和反序列化的帮助类:
例如我们通过二进制的形式来进行序列化,我们都知道可以序列化的类必须打上标记,标识是否可以序列化,也可以在成员属性上定义。
~~~
///
/// 序列化和反序列化辅助类
///
public class SerializableHelper
{
public string Serializable(object target)
{
using (MemoryStream stream = new MemoryStream())
{
new BinaryFormatter().Serialize(stream, target);
return Convert.ToBase64String(stream.ToArray());
}
}
public object Derializable(string target)
{
byte[] targetArray = Convert.FromBase64String(target);
using (MemoryStream stream = new MemoryStream(targetArray))
{
return new BinaryFormatter().Deserialize(stream);
}
}
public T Derializable(string target)
{
return (T)Derializable(target);
}
}
~~~
下面给出简单的示例代码,还是使用上面的颜色对象为例。我们修改颜色类中的Clone方法
~~~
#region IColorDemo 成员
public IColorDemo Clone()
{
string target= SerializableHelper.Serializable(this);
return SerializableHelper.Derializable(target);
}
#endregion
程序的测试代码如下:
static void Main(string[] args)
{
IColorDemo color = new RedColor();
color.Red = 255;
IColorDemo color1 = color.Clone();
color1.Red = 234;
Console.WriteLine(color.Blue == color1.Blue);
System.Threading.Thread.Sleep(10000);
}
~~~
程序的运行结果为false,肯定二个对象是不同的,通过序列化和反序列化形成新的对象。其实只要是项目中要使用原型模式进行对象复制的情况下,都可以通过序列化的形式来进行深复制。
### 七、原型模式使用总结
原型模式作为创建型模式中的最特殊的一个模式,具体的创建过程,是由对象本身提供,这样我们在很多的场景下,我们可以很方便的快速的构建新的对象,就像前面分析讲解的几类场景中,可能我们通过使用对象的克隆,比通过其他几类的创建型模式,效果要好的多,而且代价也小很多。打个比方,原型模式对于系统的扩展,可以做到无缝的扩展,为什么这么说呢?比如其他的创建型工厂,如果新增一个对象类型,那么我们不管是修改配置文件的方式,还是修改代码的形式,无疑我们都是需要进行修改的,对于我们大家通用的公共应用来说这无疑是危险的,那么通过原型模式,则可以解决这样的问题,因为类型本身实现这样的方法即可,但是也有一定的缺点,每个对象都实现这样的方法,无疑是很大的工作量,但是在某些特殊的环境下,或者实际的项目中,可能原型模式是好的选择。
### 八、系列进度
创建型
1、[系统架构技能之设计模式-单件模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/02/1841390.html)
2、[系统架构技能之设计模式-工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/11/30/1892227.html)
3、[系统架构技能之设计模式-抽象工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/01/1893388.html)
4、[系统架构技能之设计模式-创建者模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/02/1894771.html)
5、[系统架构技能之设计模式-原型模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/04/1896471.html)
结构型
1、系统架构技能之设计模式-组合模式
2、系统架构技能之设计模式-外观模式
3、系统架构技能之设计模式-适配器模式
4、系统架构技能之设计模式-桥模式
5、系统架构技能之设计模式-装饰模式
6、系统架构技能之设计模式-享元模式
7、系统架构技能之设计模式-代理模式
行为型
1、系统架构技能之设计模式-命令模式
2、系统架构技能之设计模式-观察者模式
3、系统架构技能之设计模式-策略模式
4、系统架构技能之设计模式-职责模式
5、系统架构技能之设计模式-模板模式
6、系统架构技能之设计模式-中介者模式
7、系统架构技能之设计模式-解释器模式
### 九、下篇预告
下篇将会针对外观模式进行讲述,该模式也是结构型模式中很有特点设计模式之一,该 模式是将现有系统中的一些细粒度的东西通过外观对象包装起来,在应用程序中访问这些方法的时候,通过外观类的形式,提供统一的访问入口,并且具体的细节,应用程序并不需要知道,这样就会降低程序调用的复杂性,由于本人水平有限,不足或者有错误的地方,请大家批评指正,请大家继续支持我,谢谢。
### 十、Demo下载
[下载本文Demo](http://files.cnblogs.com/hegezhou_hot/ProtoTypical.rar)
';
设计模式系列-创建者模式
最后更新于:2022-04-01 20:25:26
### 一、上篇回顾
上篇我们主要讲述了抽象工厂模式和工厂模式。并且分析了该模式的应用场景和一些优缺点,并且给出了一些实现的思路和方案,我们现在来回顾一下:
抽象工厂模式:一个工厂负责所有类型对象的创建,支持无缝的新增新的类型对象的创建。这种情况是通过配置文件来实现的,通过字典映射的方式来实现,不过可能效率上有点低下,可以通过优化的方式
来做,上篇中我们也给出了委托的工厂实现形式,相比之前的简单工厂模式和工厂模式有了更好的灵活性,并且对具有依赖关系或者组合关系的对象的创建尤为适合。
上篇中,有不少的朋友提出了一些意见和建议,首先很感谢大伙的支持和鼓励,有朋友提出来,我画的图不够专业,专业人士应该用UML建模图来搞,我怎么说呢?我也同意这样的说法,但是我发现我通过
另外的直观的图形,大家一看就能更明白,结合代码,当然好的UML图,已经能表述清楚设计的思路和大体实现了,不过说实话,我看着就有点类,特别是UML图复杂的时候。所以我还是暂时先用这种一般的图
形来表述我理解的设计模式的思想,看看大伙是什么看法和意见,如果说都说说UML图的话,那么后面的相关模式,我会主要以UML专业图来绘制。
我这里总结下我们以后项目中的可能会用到设计模式 之处或者系统架构的时候,一般情况下有这样的几类方案,我们可以在考虑系统的低耦合性的时候的设计:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b282259.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/633b606b0863_B56F/image_2.png)基本上来说能掌握上面的几类情况,基本上设计出来的系统至少是可用的,不知道大家有没有更多意见和建议。有的请提出来,我会备
注在文章中。
### 二、摘要
本文主要是针对创建型模式中的创建者模式进行讲述,创建者模式是创建型模式中最负责的一个设计模式了,创建者负责构建一个对象的各个部分,并且完成组装的过程,我们可以这么理解创建者模式,创建者模式类似与一个步骤基本固定,但是每个步骤中的具体形式却又可以变化的这类对象的创建。也许这样说还是太抽象了,我们这么来理解吧,我感觉让人最容易理解的形式还是图形化的形式,不但接受起来容易,并且让人映象深刻,不知道大家是不是和我有同感呢?下面我们给出一个简单的例子,通过图形化的流程来说明吧:我们这里以我们大伙平时最常见的做饭为例吧:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b29e8f9.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/633b606b0863_B56F/image_6.png)可能我这里给出的流程只是我个人理解的或者看到的过程,不代表全部,呵呵,这里只是事例性的说明。
### 三、本文大纲
a、上篇回顾。
b、摘要。
c、本文大纲。
d、创建者模式的特点及使用场景。
e、创建者模式的实现方案。
f、创建者模式使用总结。
g、系列进度。
h、下篇预告。
### 四、创建者模式的特点及使用场景
创建者模式主要是用于创建复杂的一些对象,这些对象的创建步骤基本固定,但是可能具体的对象的组成部分却又可以自由的变化,现实中的例子很多,但是可能大伙都比较容易理解的就是,我们的自己花钱配置的台式机或者笔记本,可以这样理解,这些硬件设备的各个零件,不管是CPU是Intel的还是AMD的,显卡是华硕的还是小影霸的,不管硬盘是西部数据的还是希捷的,其实想表述的意思就是对象的具体的组成部分可以是变化的,但是可能我们发现对象的这些组成部分的组织起来的过程是相对固定的,那么我们就可以用创建者模式来做,并且我们引入一个引导者(Director)来引导这个对象的组装过程。可以简单用图形化的过程来描述如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b2bc6f4.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/633b606b0863_B56F/image_10.png)我们上面说明了一个服装的大概生产过程,这里生产的顺序可能会发生变化,或者生产的帽子,上衣等都会发生变化,但是服装的组装过程基本上变化不大,都是需要帽子,上衣,裤子的,这时候我们可以通过引导着负责组装这样的过程,然后我们在具体的每个部分可以是抽象接口,根据不同的实现创建不同的帽子来完成变化。
### 五、创建者模式的实现方案
####5.1、经典的创建者模式实现
-
- 我们先给出经典创建者模式的一个实现形式,然后针对这个经典模式后面提出几个改进方案,我们这里以上面讲述的服装的过程作为例子来说明下创建者模式的原理和思想,希望大家也能灵活的运用到实际的项目中去。达到学以致用的目的。
我们来看看具体的代码实现:
~~~
///
/// 创建对象组织的所有构造步骤接口
///
public interface IBuider
{
void BuilderPart1();
void BuilderPart2();
void BuilderPart3();
}
~~~
定义一个服装对象:
~~~
///
/// 服装对象
///
public class Dress
{
///
/// 构建帽子
///
public void BuildHat()
{
throw new NotImplementedException();
}
///
/// 构建上衣
///
public void BuilderWaist()
{
throw new NotImplementedException();
}
///
/// 构建裤子
///
public void BuilderTrousers()
{
throw new NotImplementedException();
}
}
~~~
实现创建对象的具体步骤:
~~~
public class Builder : IBuider
{
private Dress _dress;
public Builder(Dress dress)
{
this._dress = dress;
}
public void BuilderPart1()
{
this._dress.BuildHat();
}
public void BuilderPart2()
{
this._dress.BuilderWaist();
}
public void BuilderPart3()
{
this._dress.BuilderTrousers();
}
public Dress Build()
{
return this._dress;
}
}
~~~
通过指导者指导对象的创建,而具体的对象的创建还是靠对象本身提供的相应方法,Builder只是调用对象的方法完成组装步骤。Builder内部提供一个返回构造后完整对象的方法,上面给出的方法是
Build()方法。
~~~
///
/// 指导者
///
public class Director
{
public void Build(IBuider builder)
{
builder.BuilderPart1();
builder.BuilderPart2();
builder.BuilderPart3();
}
}
~~~
通过上面的代码,我们给出了经典创建者模式的核心代码形式,那么针对上面无疑有以下的几个缺点:
1、Ibuilder接口必须定义完整的组装流程,一旦定义就不能随意的动态修改。
2、Builder与具体的对象之间有一定的依赖关系,当然这里可以通过接口来解耦来实现灵活性。
3、Builder必须知道具体的流程。
那么针对上面的几个问题,我们如何来解决呢?我想前面的创建型模式已经给我了足够的经验,还是通过配置文件或者其他的形式来提供灵活性。
-
#### 5.2、创建者模式特性+委托实现
####针对上面讲述的例子我们可以考虑如下的方式进行改进:
我们先定义一个构造每个对象部分的委托,并且这个方法的参数是动态变化的:
~~~
///
/// 定义通用的构造部分的委托
///
public delegate void BuildHandler(params object[] items);
~~~
我们通过定义标记来标识对象中的每个部分的构造步骤
~~~
///
/// 为对象中的每个步骤打上标记
///
[AttributeUsage(AttributeTargets.Method,AllowMultiple=false)]
public class BuildAttribute : Attribute
{
private MethodInfo hander;
private int stepSort;
public MethodInfo BuildHandler
{
get
{
return this.hander;
}
set
{
this.hander = value;
}
}
public int StepSort
{
get
{
return this.stepSort;
}
set
{
this.stepSort = value;
}
}
}
~~~
构造对象的统一接口
~~~
///
/// 创建对象组织的所有构造步骤接口
///
public interface IBuider
{
void Build() where T : class,new();
}
~~~
下面给出具体的Builder的缓存实现方案代码
~~~
public class CommonBuilder : IBuider
{
///
/// 缓存每个对象的具体的构造步骤
///
private Dictionary> steps = null;
public void Build(T ob) where T : class, new()
{
//从缓存中读取指定类型的项
List handlers = steps[typeof(T)];
foreach (BuildHandler handler in handlers)
{
handler();
}
}
}
~~~
给出一些获取某个类型内部的所有具有我们的自定义特性标记的MethodInfo列表
~~~
public List GetMethodInfoList() where T : class, new()
{
//从缓存中读取指定类型的项
List methods = new List();
T target = new T();
MethodInfo[] methodList= typeof(T).GetType().GetMethods();
BuildAttribute[] attributes = null;
foreach (MethodInfo info in methodList)
{
attributes= (BuildAttribute[])info.GetCustomAttributes(typeof(BuildAttribute), true);
if (attributes.Length > 0)
methods.Add(info);
}
return methods;
}
~~~
获取所有的特性,一般使用这个方法即可获取所有的具有标记该特性的方法列表和相应的步骤:
~~~
public List GetBuildAttributeList() where T : class, new()
{
List attributes = new List();
BuildAttribute[] attributeList = null;
BuildAttribute attribute = null;
foreach (MethodInfo info in this.methods)
{
//设置特性中要执行的方法
attributeList = (BuildAttribute[])info.GetCustomAttributes(typeof(BuildAttribute), true);
if (attributeList.Length > 0)
{
attribute = attributeList[0];
attribute.BuildHandler = info;
attributes.Add(attribute);
}
}
//缓存步骤
steps.Add(typeof(T), attributes);
return attributes;
}
~~~
具体的Build中的调用代码实现:
~~~
public T Build(T ob) where T : class, new()
{
List attributeList = GetBuildAttributeList();
T target=new T();
//构造对象的过程
foreach (BuildAttribute item in attributeList)
{
item.BuildHandler.Invoke(target,null);
}
return target;
}
~~~
这样我们就完成了一个通用的基于标记的自动发现某个类型的标记方法步骤的通用代码实现,可能大家感觉这样的方式还是挺麻烦的,那么我们还有没有更好的改进方案呢?因为每次打标记我还是感觉挺麻烦的,而且代码量分布的也比较广泛,我想通过统一配置管理的方式,当然也是可以的,那么我们可以通过下面的方式来进行扩展。
-
#### 5.3、创建者模式配置文件方式实现
配置文件的方式实现创建者,这个怎么说呢,上面的抽象工厂的模式中,我们主要采用了这样的方式来实现配置的灵活性和扩展性,其实创建者也是一样的,我们来看看配置文件吧,我想就看配置文件就大概知道了,具体的应用代码了,请看下图,粗略描述了实现的思路:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b2db1ae.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/633b606b0863_B56F/image_7.png)
我这里给出配置文件的父子级节点示例:
~~~
~~~
我们这里通过在Build实现中读取配置文件中的所有的步骤,放在字典中。给出示例代码
~~~
///
/// 创建对象组织的所有构造步骤接口
///
public class Buider : IBuider
{
private Dictionary> steps = null;
public Buider()
{
steps = new Dictionary>();
//读取配置文件!
//将配置文件中的类名和方法名取出,然后通过反射取到这个类型下的所有方法,根据配置中的步骤和方法名添加到
//步骤列表中,然后缓存到字典中
steps.Add(Type.GetType(""), new List());
}
public T Build() where T: class,new()
{
T target = new T();
//从字典中找到对应的缓存列表,执行构造过程
List list = steps[typeof(T)];
//执行构造
foreach (MethodInfo info in list)
{
info.Invoke(target, null);
}
return target;
}
}
~~~
通过上面的几步配置就可以完成相应的构建过程,这时候我们的指导者的工作就简单了,就是只是简单的通过使用Build中的通用方法
~~~
public class Director
{
public void Build(IBuider builder) where T:class,new()
{
builder.Build();
}
}
~~~
只要通过上面的步骤就完成了创建者模式的通用实现方案。
### 六、创建者模式使用总结
通过上面的给出的几类不同的实现方案我们知道,创建者模式是一个对对象的构建过程“精细化”的构建过程,每个部分的构建可能是变化的,但是对象的组织过程是固定的,通过这种统一的创建方式,无疑增加了我们设计上的灵活性,当我们在构建复杂对象的时候,我们如果发现每个部分可能都是变化的,并且是多个不同的构建步骤的时候,我们可以考虑使用创建者模式。相比我们之前讲述的工厂和抽象工厂模式区别还是很大的,我们发现创建者适合这类复杂对象的创建,对于抽象工厂可能就无法完成这样的组装工作,而且创建者模式是把复杂对象的内部创建方法进行调用,组织协调了对象的各个部分前后顺序的控制。简单的描述创建者就是这样的情况:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b308926.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/633b606b0863_B56F/image_13.png)
由于本人水平有限,或者讲述能力有限,表达思路错误或者想法错误,请大家批评指出,如果您有更好的意见或者想法,请提出讨论,欢迎大家提出宝贵意见和建议。
### 七、系列进度。
创建型>
1、[系统架构技能之设计模式-单件模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/02/1841390.html)
2、[系统架构技能之设计模式-工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/11/30/1892227.html)
3、[系统架构技能之设计模式-抽象工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/01/1893388.html)
4、[系统架构技能之设计模式-创建者模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/02/1894771.html)
5、系统架构技能之设计模式-原型模式
结构型>
1、系统架构技能之设计模式-组合模式
2、系统架构技能之设计模式-外观模式
3、系统架构技能之设计模式-适配器模式
4、系统架构技能之设计模式-桥模式
5、系统架构技能之设计模式-装饰模式
6、系统架构技能之设计模式-享元模式
7、系统架构技能之设计模式-代理模式
行为型>
1、系统架构技能之设计模式-命令模式
2、系统架构技能之设计模式-观察者模式
3、系统架构技能之设计模式-策略模式
4、系统架构技能之设计模式-职责模式
5、系统架构技能之设计模式-模板模式
6、系统架构技能之设计模式-中介者模式
7、系统架构技能之设计模式-解释器模式
### 八、下篇预告。
下篇将会针对原型模式进行讲述,该模式也是创建型模式中很有特点设计模式之一,该 模式是利用现有的一个对象进行克隆的过程产生一个新的对象,当然这里的复制对象可以是2种,深复制和浅复制,在这个系列的总结中如果您有好的想法或者创意,请提出来,希望大家多提宝贵意见,错误之处还请指出,请大家继续支持。
';
系统架构技能之设计模式-抽象工厂模式
最后更新于:2022-04-01 20:25:24
### 一、上篇回顾
上篇我们主要讲述了简单工厂模式和工厂模式。并且分析了每种模式的应用场景和一些优缺点,我们现在来回顾一下:
简单工厂模式:一个工厂负责所有类型对象的创建,不支持无缝的新增新的类型对象的创建。
工厂模式:多个工厂负责多个类型对象的创建,每个工厂只负责具体类型对象的创建,支持无缝的新增类型对象的创建,需要实现工厂接口类和具体的类型对象类。
我们来简单的对比下这2个模式的优缺点:
| 模式名称 | 优点 | 缺点 |
|-----|-----|-----|
| 简单工厂模式 | 一个工厂负责所有对象的创建,简单灵活 | 不符合高内聚的原则,不支持无缝的扩展 |
| 工厂模式 | 可以无缝的新增类型,每个工厂职责单一,符合高内聚的原则 | 工厂类太多,难以维护。 |
工厂模式,很优雅的解决了应用程序使用对象时的无限new()的操作,同时降低了系统应用之间的耦合性,提高了系统的可维护性和适应性。
### 二、摘要
本文主要是针对创建型模式中的抽象工厂模式进行讲述,抽象工厂模式是在简单工厂模式的基础上扩展而成的新模式,将简单工厂中的对象的创建过程进行了很优雅的动态配置来完成无缝的扩展,当然通过一些扩展,可以构建出可支持动态新增或者删除对象的抽象工厂模式。本文将会给出具体的实现方案,相比工厂模式,抽象工厂模式是一个工厂负责多个对象的创建,返回的具体的类型是这个对象的抽象类型。这样,在客户端引用的时候只需要使用这个工厂返回的对象类型,抽象工厂会自动根据对象的类型动态的创建这个类型对象的实例。大体的过程如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b2166d0.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/592b39ea7052_8409/image_2.png)
上面的图片呢,主要是针对经典的抽象工厂模式给出了一个实现草图的模拟,而我们在实际的项目中可能并不希望给出这么多的抽象工厂工厂实现,我只想给出一个通用的抽象
工厂实现,通过静态方法直接调用,返回我想要的对象类型的实例,而且这个对象类型是可以动态配置的,那么我们如何做到呢?这就是本篇需要讨论的实现方案。本篇将会从
以下几点进行讲述抽象工厂模式:
1、抽象工厂模式的简单实例代码-这里给出的是经典的抽象工厂模式实例代码。我们从经典的实例代码中可以看出这个工厂模式的一些缺点。
2、根据经典工厂模式的缺点,我们给出改进的方案,进一步给出项目中可以使用的通用方案实现。
3、给出上篇中的通过委托来实现的工厂模式方案。
4、通过特性+反射的形式来动态的创建对象。
### 三、本文大纲
a、上篇回顾。
b、摘要。
c、本文大纲。
d、抽象工厂模式的特点及使用场景。
e、抽象工厂模式的实现方案。
f、抽象工厂模式使用总结。
g、系列进度。
h、下篇预告。
### 四、抽象工厂模式的特点及使用场景
抽象工厂可以说是三类工厂模式中使用最广泛的,也是最受大家喜爱的模式之一,因为抽象工厂模式解决了一系列相互依赖的对象或者有组合关系的对象的创建过程。举个简单的例子来
说,我们以电脑的显卡和风扇来说吧,我们知道显卡一般在玩游戏的时候,由于渲染图形会产生大量的热量,如果没有好的风扇那么可能无法达到好的散热的效果,这个时候我们可以把显卡和
风扇的创建放在一个抽象工厂中进行创建,因为这2个对象是具有依赖关系的对象,那么我们来给出这个例子的完整实例代码:
先看看2个对象类型的接口和抽象工厂的接口定义
~~~
///
/// 定义显卡抽象对象接口
///
public interface IDisplayCard
{
}
///
/// 定义显卡风扇抽象对象接口
///
public interface IDisplayFan
{
}
///
/// 定义显卡设备抽象工厂接口
///
public interface IAbstractDriveFactory
{
IDisplayCard CreateDisplayCard();
IDisplayFan CreateDisplayFan();
}
我们来看看具体类型的实现和抽象工厂的具体实现。
///
/// 定义华硕显卡的具体对象
///
public class DisplayCardAsus : IDisplayCard
{
}
///
/// 华硕显卡配套风扇
///
public class DisplayFanAsus : IDisplayFan
{
}
///
/// 华硕显卡具体实现工厂
///
public class DriveFactoryAsus : IAbstractDriveFactory
{
IDisplayCard CreateDisplayCardAsus()
{
return new DisplayCardAsus();
}
IDisplayFan CreateDisplayFanAsus()
{
return new DisplayFanAsus();
}
}
~~~
通过上面的代码,我们给出了抽象工厂的一个经典实例的实现方案,当然这不是我们开发中使用的实际形式,那么实际我们在项目中如何使用这个抽象工厂模式呢?我们一般是改进的方
案去使用这个抽象工厂模式,我们如何改进呢?对于目前的,如果我不光创建显卡设备和配套的风扇设备,我还想创建其他的类型的东西,这时候可能我们定义的抽象工厂就无法满足具有相互
依赖或者组合关系的对象类型实例的创建工作了,那么我们如何改进呢,这就是下面要讲述的几类方案。
### 五、抽象工厂模式的实现方案
#### 5.1、通过配置文件来实现
- 我们先给出基于上面的经典抽象工厂的一个改进的方案,可以支持动态配置的抽象工厂,一个工厂负责动态的创建一些列的可动态配置的对象列表,我们如何做呢,我想一提到配置。大家都知道要么是通过XML文件来实现或者是通过泛型集合来做。我们这里可以提供的方案是这样的,通过工厂初始化时从配置文件中读取配置项,构造一个字典,然后从这个字典中查询要创建的类型是否在字典中,如果在字典中存在则创建这个类型的对象,否则返回NULL,我们这里通过泛型来实现。
- 我们来看看具体的代码实现吧:
~~~
///
/// 定义抽象工厂接口
///
public interface IAbstractFactory
{
///
/// 通用的泛型对象创建工厂
///
///
///
T Create();
}
~~~
给出具体的实现这个接口的抽象工厂类
~~~
///
/// 具体的通用工厂实现
///
public class AbstractFactory : IAbstractFactory
{
private static readonly IDictionary instances = null;
public static AbstractFactory()
{
//从具体的配置项中读取,从配置文件中读取或者通过某个方法来硬编码实现等。
//这里推荐的做饭是从配置文件中读取。
instances = new Dictionary();
instances.Add(Type.GetType(""), Type.GetType(""));
instances.Add(Type.GetType(""), Type.GetType(""));
}
public T Create()
{
if (!instances.ContainsKey(typeof(T)))
return default(T);
Type typeInstance = instances[typeof(T)];
T obj = (T)Activator.CreateInstance(typeInstance);
return obj;
}
}
~~~
- 通过上面给出的代码,基本上可以满足一般项目的需求,大家当然有好的思路和建议也可以提出,给出更好的改进方案,下面我给出大概的配置文件格式,其实就是父子级节点,父级节点是负责创建的工厂
- 类,那么这个父节点下的子节点就是工厂要创建的具体的对象类型。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b23e877.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/592b39ea7052_8409/image_6.png)
上图中描述的思路,我们大概知道了,对应这样的一个支持多个具有依赖关系或者组合关系的对象的动态抽象工厂的实现,那么如果我们想实现支持多个具有依赖关系或者组合
关系的不同的创建形式的通用创建工厂时,我们如何来做呢?同上面的思路,只不过我们外部需要再添加一个字典,负责类型和抽象工厂的映射,即抽象工厂可以创建的字典列
表及抽象工厂具体实例类型之间的键值对关系,或者通过配置文件来组织父子级的关系。我们大概的看下配置文件的组织吧:
~~~
~~~
那么具体的抽象工厂的代码又如何组织呢?如下形式:
~~~
///
/// 具体的通用工厂实现
///
public class AbstractFactory : IAbstractFactory
{
///
/// 工厂与工厂能够创建的对象类型字典之间的映射字典
///
private static readonly IDictionary> typeMapper = null;
private Type factoryType = null;
public static AbstractFactory()
{
//从具体的配置项中读取,从配置文件中读取或者通过某个方法来硬编码实现等。
//这里推荐的做饭是从配置文件中读取。
//根据配置文件中的ObjectInstance 节点放在对应的工厂下的字典中
//每个工厂节点FactorySection 就会创建一个字典,并且将这个工厂能够创建的类型放在这个字典中
typeMapper = new Dictionary>();
}
public AbstractFactory(string typeName)
{
this.factoryType = Type.GetType(typeName);
}
public T Create()
{
if(typeMapper.ContainsKey(this.factoryType))
return default(T);
Dictionary instances = typeMapper[this.factoryType];
if (!instances.ContainsKey(typeof(T)))
return default(T);
Type typeInstance = instances[typeof(T)];
T obj = (T)Activator.CreateInstance(typeInstance);
return obj;
}
}
~~~
通过上面的代码我们就给出了一个通用的抽象工厂的可行的解决方案。
#### 5.2、通过委托来实现工厂模式
我们先要定义一个委托:
public delegate string DelegateFunctionHandler(string userName);
基于这个委托的工厂实现方案
~~~
///
/// 具体的通用工厂实现
///
public class DegelateFactory
{
private DelegateFunctionHandler handler = null;
public static DelegateFunctionHandler Create()
{
if (handler == null)
handler = new DelegateFunctionHandler(this.Test);
return handler;
}
public string Test(string name)
{
return "Test!";
}
}
~~~
工厂返回一个委托类型的对象,当然我上面为了简单给出的test方法其实就是工厂内部的方法,当然这里还可以进行相应的改进,也可以通过配置文件来完成,通过配置文件把相应相
应的委托事件方法,通过配置来通过工厂动态的创建。下面给出个思路吧,具体的实现我就不贴出来了:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b26293b.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/592b39ea7052_8409/image_10.png)也希望大家给出更好的实现思路和方案。希望能多多的交流。
### 六、抽象工厂模式使用总结
通过上面的实现方式和思路,我们来对比一下抽象工厂、工厂模式、简单工厂模式之间的差异和相同点。
相同点:
1、都是为客户调用程序与具体的对象类型之间提供了一个解耦作用,这里怎么说呢?其实就是应用程序不关心这个对象是怎么出来的,只关系如何使用这个对象,而且以后就算对象发生变化,那么也不需
要修改用户应用程序的代码。
2、提高了程序的可维护性和低耦合性。
异同点:
1、简单工厂模式:是简单的一些列没有任何依赖关系的对象的创建,内部包含复杂的逻辑关系,一半是通过配置或者参数来进行创建对象,适合对象类型不多,并且不会经常新增的情况下。
工厂模式:每个工厂负责具体类型对象的创建,提供了可以动态新增产品类型的创建,并不需要修改现有的程序就可以无缝的新增产品类型。
抽象工厂模式:支持动态的新增对象类型和新增工厂类型,实现多种依赖关系的对象或者组合关系的创建,适合现有项目中的对象创建过程。
2、简单工厂模式:内部逻辑复杂,不符合高内聚的原则。
工厂模式:每次新增一个对象类型,就必须新增一个对应的创建工厂,无疑这是一个非常大的工作量。
抽象工厂模式:是在简单工厂模式的基础上经过改进具有前2个模式的优点,又屏蔽了他们的一些缺点。
当然我们在具体的项目中,还是需要具体的情况具体分析,一般情况下,我们对于这种数据库平滑迁移时,简单工厂可能比其他2类工厂更容易做,也很灵活。
### 七、系列进度。
创建型>
1、[系统架构技能之设计模式-单件模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/02/1841390.html)
2、[系统架构技能之设计模式-工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/11/30/1892227.html)
3、[系统架构技能之设计模式-抽象工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/12/01/1893388.html)
4、系统架构技能之设计模式-创建者模式
5、系统架构技能之设计模式-原型模式
结构型>
1、系统架构技能之设计模式-组合模式
2、系统架构技能之设计模式-外观模式
3、系统架构技能之设计模式-适配器模式
4、系统架构技能之设计模式-桥模式
5、系统架构技能之设计模式-装饰模式
6、系统架构技能之设计模式-享元模式
7、系统架构技能之设计模式-代理模式
行为型>
1、系统架构技能之设计模式-命令模式
2、系统架构技能之设计模式-观察者模式
3、系统架构技能之设计模式-策略模式
4、系统架构技能之设计模式-职责模式
5、系统架构技能之设计模式-模板模式
6、系统架构技能之设计模式-中介者模式
7、系统架构技能之设计模式-解释器模式
### 八、下篇预告。
下篇将会针对创建者模式进行讲述,该模式也是创建型模式中最复杂的设计模式之一,该模式是对一个对象的各个创建部分进行划分,最后创建出完整的对象,当然这里面的实现方式可以说还是 那几类思路,我将会给出几个方案的关键代码,希望大家多提宝贵意见,错误之处还请指出,请大家继续支持。
';
系统架构技能之设计模式-工厂模式
最后更新于:2022-04-01 20:25:22
### 一、开篇
一个多月没有写文章了,一方面是由于家庭的原因,还有一方面是因为工作上的原因,所以在这里给大家说抱歉了,这段时间也是有很多热心的朋友,一直询问我,什么时候能把相关的
系列文章写完,其实我也特别的想赶快的把相关的文章书写完毕,不过现在真的是有时候力不从心,家庭和工作上的事情需要都处理好,所以属于个人思考的时间可能就会相对的少一些了,不
过我会继续努力,出时间来把下面的这几个系列写完:
1、[系统架构技能之设计模式-系列索引](http://www.cnblogs.com/hegezhou_hot/archive/2010/11/30/1891672.html)
2、[系统架构师-基础到企业应用架构-系列索引](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/12/1824345.html)
3、[Step by Step-构建自己的ORM系列](http://www.cnblogs.com/hegezhou_hot/archive/2010/09/17/1829510.html)
当然可能在我写的过程中又会产生新的想法或者思路,我会提出来,并且给出相应的实现方案的。希望大家能够集思广益,能够创造出适合大家的通用的解决某类 问题的通用解决方案,那么就真的是大功告成了,呵呵,闲话不多说了,我们还是来实质性的东西吧,本文主要是讲述设计模式中最经典的创建型模式-工厂模式,本文将会从以下几点对工厂模式进行阐述。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-18_5714bc3610e00.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/36464751dff5_77FC/image_2.png)
本文将会从上面的四个方面进行详细的讲解和说明,当然会的朋友可以之处我的不足之处,不会的朋友也请我们能够相互学习讨论。
### 二、摘要
本文将会主要是结合项目中的一些实例作为实例来分析工程模式的使用方式和何时使用工程模式,并且分析工程模式的有点和它解决的问题,在我们实际的项目中何时能使用到它,或者说我们在什么情况下,应该考虑使用工厂模式来解决项目中的问题,一般情况下我们可以这样理解设计模式,设计模式是一种方案,为我们遇到与设计模式提出的应用场景想象或者相仿的场景中,这类问题通常是经常发生或者是经常遇到的问题的通用解决方案。
本文依然是采用图文讲解的形式来分析工程模式在项目中出现的位置,并且给出几个灵活的实现方案。主要针对的实现方式有:通过配置文件,通过类型,通过委托,通过特性等来实现工厂。
### 三、本文大纲
a、开篇。
b、摘要。
c、本文大纲。
d、工厂模式的特点及使用场景。
e、工厂模式的实现方案。
f、工厂模式使用总结。
g、系列进度。
h、下篇预告。
### 四、工厂模式的特点及使用场景
#### 4.1、工厂模式简介
工厂模式是创建型模式中最典型的模式,主要是用来创建对象,减少我们在使用某个对象时的new()操作,我相信大家都有这样的困惑,目前我所在的项目都在程序开发的过程中,还是有很多的new()操作出现在表现层中,并没有通过工厂来创建对象,一方面可能是因为我们自身比较懒,不规范项目的编码形式,另外一方面也是由于项目的进度比较紧,没有那么多的时间去完成工厂的统一创建,当然对于这样的动态创建对象的工厂,推荐的做法还是我们后面会讲到的创建型模式--《抽象工厂模式》来解决吧。
如果您并不知道工厂模式是用来干什么的,我们可以通过如下举例来说明,例如我们现在有个矿泉水加工厂,加工矿泉水,我们现在知道有矿泉水这个对象,那么当我批量生产矿泉水的时候,我们就通过工厂来批量的生产,等于我们程序中的批量创建对象。这时候我有很多个对象,也就是很多游客,他们每人都要一瓶矿泉水,这时候如果说把游客比作不同的应用程序模块,都要使用矿泉水这个对象,那么我是不是应该每个应用程序都在使用这个对象的时候,我使用new()操作呢?,无疑这不是一个好的方案。我们来看看图形化的描述吧?
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-18_5714bc362efa7.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/36464751dff5_77FC/image_6.png)这种情况下,不同的游客需要矿泉水的时候,我就new()一个矿泉水和我找个加工厂生产矿泉水明显是有差别的,这个时候,游客不应该和矿泉水有关联关系了,而且游客不知道,矿泉水是怎么生产出来的,也不需要关心这些东西。
那么我们应该如何去解决这样的问题呢?基于面向对象的变成设计时,原则就是低耦合,对象和对象之间。那么对象之间的引用关系,可以通过抽象出接口,通过借口的依赖来解耦,降低系统的耦合性。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-18_5714bc365c03d.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/36464751dff5_77FC/image_8.png)假如这个时候我修改对象服务的名称,那么我是不是必须把所有的调用这个对象服务应用程序代码都进行修改?这个是必须的,否则程序无法编译通过的。但是如果我们使用工厂模式的时候呢?有什么不同呢?我们来看看:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-18_5714bc3678442.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/36464751dff5_77FC/image_10.png)上面是添加了工厂模式之后的情况,上面就算是你修改了类名之后,只需要修改工厂中的New出来的类即可,当然如果你要是通过返回接口的形式的话,再不修改接口命名的前提下,如何修改类方法都是可行的,并且通过工厂模式,无疑降低了应用程序与对象之间的耦合性,通过工厂来解耦,提供程序的应对变化的适应能力。
#### 4.2、工厂模式的使用场景
工厂模式一般用于创建一类对象,而不用每次在使用时通过new()对象才能使用对象,而是通过工厂来完成对象的创建,这样不但提供了统一创建对象的入口,而且对于程序的可维护和可测试性都有很大的提高。总体来说如下场景使用工厂模式非常合适:
1、工厂负责创建某一类对象的时候,或者说工厂的职责比较单一时,如果说多个类型的对象时候,用工厂模式就不如使用抽象工厂了
2、一般比较少的积累对象,可以通过类型的判定创建不同的对象时,也是可以通过工厂模式来完成,例如多数据库的支持,我们在设计数据访问层时,利用简单对象工厂,通过枚举或者配置文件的形式,来动态的创建数据访问层实例。
3、一般来说类型单一的对象,或者类型比较少的时候,使用工厂模式来创建对象可以解决一类问题。还可以通过一个总的工厂,来创建多个工厂,然后多个工厂负责创建相应的实例,
有点类似我们平时说的目录结构似的。
类似如下的形式,大家一看就明白了:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-18_5714bc369a24a.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/36464751dff5_77FC/image_12.png)
等于是不同层级的工厂,具有不同的职责和任务。
### 五、工厂模式的实现方案
#### 5.1、工厂模式的配置文件实现。
我们先看配置文件的配置内容
~~~
default
MSSQLServer
~~~
定义要创建的对象实例统一接口
~~~
///
/// 所有的数据访问接口
///
public interface IDbAccess
{
}
~~~
实现这个接口的具体类
~~~
public class SQLServer : IDbAccess
{
//相关的方法
public System.Data.SqlClient.SqlConnection Connection
{
get
{
return new System.Data.SqlClient.SqlConnection();
}
}
}
~~~
负责创建返回类型为IDbAccess的数据访问层对象实例
~~~
public class DBFactory
{
public IDbAccess Create()
{
IDbAccess instance = null;
System.Xml.XmlDocument doc=new System.Xml.XmlDocument();
doc.LoadXml("");
XmlElement root = doc.DocumentElement;//XML文档的根节点
XmlNode node = root.SelectSingleNode("DataBaseType");
switch (node.InnerText)
{
case "SQLServer":
instance = new SQLServer();
break;
case "Oracle":
instance = new Oracle();
break;
default:
break;
}
return instance;
}
}
~~~
具体的控制台输出测试代码如下:
~~~
class Program
{
static void Main(string[] args)
{
DBFactory factory = new DBFactory();
IDbAccess dbaccess = factory.Create();
//使用相应的数据访问对象即可。
}
}
~~~
#### 5.2、通过枚举来实现。
通过枚举来实现后,工厂类的创建代码如下:
~~~
public class DBFactory
{
public IDbAccess CreateByEnum(DbType dbType)
{
IDbAccess dbAccess = null;
switch ((int)dbType)
{
case (int)DbType.SQLServer:
dbAccess= new SQLServer();
break;
case (int)DbType.Oracle:
dbAccess = new Oracle();
break;
case (int)DbType.Access:
dbAccess = new Access();
break;
default:
break;
}
return dbAccess;
}
}
~~~
相应的枚举代码如下:
~~~
public enum DbType
{
SQLServer=0,
Oracle=1,
Access=2
}
~~~
相应的控制台测试代码:
~~~
static void Main(string[] args)
{
DBFactory factory = new DBFactory();
IDbAccess dbaccess = factory.CreateByEnum(DbType.SQLServer);
//使用相应的数据访问对象即可。
}
~~~
#### 5.3、工厂模式的复杂进阶
我们上面只是定义了一种工厂,该工厂负责所有的子类对象的创建,如果说我们的工厂要求能够满足增加新的对象时,我们必须修改工厂代码,那么我们如何来做呢?我们可以这样来做。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-16_573996b1e19a6.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/36464751dff5_77FC/image_14.png)每个类型的对象都有与这个类型对应的工厂去创建,那么就算以后增加或者修改,只需要修改相应的工厂涉及的文件即可。但是这样也有很大的弊端就是工厂类太多,难以维护。优点是支持动态的增加新的对象类型,对之前的创建工作不会造成影响,我们来看看相应的代码,基于图中的几个类型。先定义对象的统一接口和工厂的接口。
先看对象接口的统一定义:
~~~
public interface IComObject
{
///
/// 重要级别
///
///
int ImportLevel();
}
~~~
工厂接口的统一定义:
~~~
public interface IComFactory
{
IComObject Create();
}
~~~
我们来看看具体的对象实现和工厂实现吧,我们这里以上图中的书为例说明创建过程
~~~
public class BookFactory : IComFactory
{
public IComObject Create()
{
return new Book();
}
}
~~~
具体的对象实现代码-实现IComObject对象接口
~~~
public class Book : IComObject
{
public int ImportLevel()
{
return 0;
}
}
~~~
>我们来看看具体的程序调用代码:
~~~
static void Main(string[] args)
{
IComFactory factory = new BookFactory();
IComObject book = factory.Create();
//使用相应的数据访问对象即可。
}
~~~
通过上面的形式,我们可以看到,后期如果新增比如说我现在要对个产品这个对象新增到系统中,那么我们只需要增加相应的对象实现类和工厂实现类即可,对其他地方不会有影响,相比上面讲述的,一个工厂创建所有的对象实例的方式无疑提供了新增对象类型创建的能力。
### 六、工厂模式使用总结
通过上面的简单实例讲解,估计高手理解起来很容易也很简单,其实本来也是很简单的,大伙不了解工厂模式的朋友,应该也能理解讲述的内容,本文前面讲述的2中方式主要是针对简单工厂模式,简单工厂模式,不符合高内聚的原则,因为所有的对象的创建工作都放在一个类的内部去完成,逻辑太复杂了,通过后面的工厂模式,将每个工厂的职责进行了更细化,每个工厂只负责具体对象类型实例的创建。这也为后期增加新的对象类型提供了不错的扩展,本文并没有给出特性+委托的工厂的实现方案,我放在下篇的抽象工厂中去讲解,也会针对配置文件,特性,委托的几种方式来给出抽象工厂模式的实现方案,当然我给出的都是很简单的例子,希望大家一看就懂,就能用在实际的项目中,可能高手会认为我讲的太浅了,一方面是因为自己没有整理好思路,时间紧迫,另一方面是因为自身能力有限,还请大家多提宝贵意见,我们总结下本文讲述的内容吧;
前面讲述了2中简单工厂模式的实现方案。通过配置文件、通过枚举来完成对象的创建,其实就是根据对象的类型来完成,也可以通过反射来完成。这里给出简单的实现:
~~~
public IDbAccess Create(string TypeName)
{
Type type = Type.GetType(TypeName);
IDbAccess obj = (IDbAccess)Activator.CreateInstance(type);
return obj;
}
~~~
其实就是这样的简短代码,给出关键代码实现吧,可能实际运行中还要进行相应的调整。
总体来说简单工厂适合项目中类型不多的情况时使用简单工厂很方便。
当项目中频繁的增加不同类型的对象时,考虑使用工厂模式,来满足这样的动态变化需求。
### 七、系列进度
创建型>
1、[系统架构技能之设计模式-单件模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/02/1841390.html)
2、[系统架构技能之设计模式-工厂模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/11/30/1892227.html)
3、系统架构技能之设计模式-抽象工厂模式
4、系统架构技能之设计模式-创建者模式
5、系统架构技能之设计模式-原型模式
结构型>
1、系统架构技能之设计模式-组合模式
2、系统架构技能之设计模式-外观模式
3、系统架构技能之设计模式-适配器模式
4、系统架构技能之设计模式-桥模式
5、系统架构技能之设计模式-装饰模式
6、系统架构技能之设计模式-享元模式
7、系统架构技能之设计模式-代理模式
行为型>
1、系统架构技能之设计模式-命令模式
2、系统架构技能之设计模式-观察者模式
3、系统架构技能之设计模式-策略模式
4、系统架构技能之设计模式-职责模式
5、系统架构技能之设计模式-模板模式
6、系统架构技能之设计模式-中介者模式
7、系统架构技能之设计模式-解释器模式
### 八、下篇预告。
下篇将会针对抽象工厂模式进行讲述,该模式也是目前项目中使用最多的一个设计模式,目前我所在的项目中,就使用到了这个模式,我会对于前面讲述的工厂模式与抽象工厂模式进行对比,并且把今天文章中提到的特性+委托的方案放出实现,希望大家多提宝贵已经,错误之处还请指出,请大家继续支持。
### 九、本文源码
下载源码
';
系统架构技能之设计模式-单件模式
最后更新于:2022-04-01 20:25:20
### 一、开篇
其实我本来不是打算把系统架构中的一些设计模式单独抽出来讲解的,因为很多的好朋友也比较关注这方面的内容,所以我想通过我理解及平时项目中应用到的一
些常见的设计模式,拿出来给大家做个简单讲解,我这里只是抛砖引玉,如果某个地方讲解的不正确或者不详细,请大家批评指出。园子里面的很多的大牛写的设计模式
都非常的经典,我这里写可能有点班门弄斧的感觉,不过我还是决定把它写出来,希望能对初学者有一定的帮助和指导的作用。当然我这里如果说某个地方解释的有问
题或者说是某个地方写的不符合逻辑之处,还请大家多多指出,提出宝贵意见。
软件工程中其实有很多总结性的话语,比如说软件=算法+数据结构等等这样的描述,当然我们这里可能算法就是泛指一些软件中的编程方法了,设计模式怎么去
理解呢?为什么要有设计模式?它能带来什么?等等这些都是我们需要讨论的问题。首先我们需要知道设计模式能带来什么。可能这才是我们学习它的主要原因,如果
说不能为我们在书写软件的过程中带来更方面的好处,那我们也不会使用和学习它。
设计模式是什么?
设计模式可以简单的理解为解决某一系列问题的完美的解决方案。我们在软件开发的过程中经常遇到设计功能实现的问题,而设计模式正是为了解决软件设计功能
实现时遇到的某一类问题的解决方案。因为一般情况下来说,我们在某个软件功能的开发过程中遇到的功能设计问题,可能是前人很早就遇到过的问题,所以通过这种
设计模式的方式来解决,能让我们在软件实现的过程中少走弯路,或者说是给我们的软件设计带来很好的灵活性和适应性。
设计模式带来了什么?
设计模式是源于实践,并且每种设计模式都包含了一个问题描述,问题涉及到的参与者并且提供了一个实际的解决方案。设计模式的好处我们可以通过下图来简单
说明:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-18_5714bc2900878.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/0526b70f3950_F181/image_2.png) 当然我这里可能总结还不完全,还请大家补充,我会更新这里面的内容。当然设
计模式带来了这么多的好处,所以我们学习设计模式就显得比较必要了,也是从事软件开发及设计必须掌握的基本技能之一。
设计模式的简单分类:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-18_5714bc291cc5c.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/0526b70f3950_F181/image_4.png) 当然这里可以简单的分为这3大类,下面我们在讲述的过程中将会分别讲解,当然我这里是以创建型模
式开始讲解,我想创建型模式也是大家项目中必备的吧?下面我就从创建型模式先来讲解。
### 二、摘要
本文将主要讲解创建型模式中的单例模式先来讲解,因为单例模式是最简单也是最容易理解的设计模式,上手快,易使用的设计模式。本文将从下面的流程来讲解
单例模式,后面讲述的设计模式也将使用这样的方式。
1、什么是单例模式?
2、单例模式的应用场景。
3、举例说明单例模式的使用。
4、总结单例模式的用法。
### 三、本文大纲
a、开篇。
b、摘要。
c、本文大纲。
d、单例模式的简介。
e、相关应用场景分析。
f、本文总结。
g、系列进度。
h、下篇预告。
### 四、单例模式的简介
本章我们将来讲述下单例模式的使用,首先我们来看看单例模式的定义:
单例模式:是一种软件设计中常用的设计模式,主要是用来控制某个类必须在某个应用程序中只能有一个实例存在。
有时候我们需要确保整个系统中只有某个类的一个实例存在,这样有利于我们协调控制系统的行为。例如:我们在某个系统中使用了发送短信的这样的服务,那么
我们可能希望通过单一的短信服务类的实例,而不是多个对象实例完成短信的发送服务。这时我们可以通过单例模式来完成。
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-18_5714bc35adb65.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/0526b70f3950_F181/image_8.png) 上图简单描述了单例模式应用的位置。
我们看看单例模式的几种实现方式:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-18_5714bc35ca58d.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/0526b70f3950_F181/image_12.png)
下面我们来举例说明下这2种方式的实现。
1、外部控制的方式
~~~
public class Instance
{
private List lists = new List();
private SendMessage sendInstance;
public SendMessage SInstance
{
get
{
return sendInstance;
}
}
public void InstanceMethod()
{
if (lists.Count == 0)
{
sendInstance = new SendMessage();
lists.Add(sendInstance);
}
else
{
sendInstance = lists[0];
}
}
}
~~~
2、内部控制方式
~~~
public class Instance1
{
private static SendMessage sendInstance;
private static object _lock = new object();
protected Instance1()
{
}
public static SendMessage SInstance
{
get
{
lock (_lock)
{
if (sendInstance == null)
sendInstance = new SendMessage();
return sendInstance;
}
}
}
}
~~~
这里有几点需要注意的地方,对于第二种方式有几个地方需要说明下,首先是要控制全局只有一个实例的类,请定义成静态实例,这样可以确保只有一个实例对
象,其次,这个对象的构造函数请声明成保护类型的成员,这样可以屏蔽通过直接实例化的形式来访问。通过这样的形式,客户可以不需要知道某个单例实例对象的内
部实现细节。一般情况下满足上面的2点需求就可以完成全局唯一访问入口的控制。当然可能在多线程的情况下采用这样的形式还会有一定的弊端,当然我们这里也简单
的讲解下相应的控制方案。方案如下:
~~~
public class CoolInstance
{
private CoolInstance()
{
}
public static readonly CoolInstance Instance = new CoolInstance();
}
~~~
看吧很简单吧,当然我们这里来简单解释下原理:
1、我们先把构造函数声明为私有的构造函数,这样我们能够屏蔽外部通过实例化的形式访问内部的成员函数。所有的成员函数的访问必须通过静态成员Instance
来完成访问。
2、这段代码通过定义公共、静态、只读的成员相当于在类被第一次使用时执行构造,由于是只读的,所以一旦构造后不允许修改,就不用担心不安全的问题。
相信对上面的介绍大家应该基本上知道单例模式的应用了,那么下面我们来看看项目中的实际应用场景及用法。
### 五、相关应用场景讲解
1、场景短信及邮件发送服务
那么我们将采用上面介绍的最“COOL”的方式来进行控制,提供发送短信及发送邮件的服务。
~~~
public class CoolInstance
{
private CoolInstance()
{
}
public static readonly CoolInstance Instance = new CoolInstance();
///
/// 发送手机短信
///
public bool SendMessage(string telNumber,string content)
{
return true;
}
///
/// 发送邮件
///
///
///
public bool SendMail(string content,string toMail)
{
return true;
}
}
~~~
我们再来看看调用类中如何书写完成调用。例如我们有个订单类,当有人新下订单时,将给卖家发送短信提醒功能。
~~~
///
/// 订单业务
///
public class Order
{
public int Save()
{
//先是将订单的相关信息生成,
this.InitOrderInfo();
//执行订单的持久化方法
int count= this.Add();
//发送短信
CoolInstance.Instance.SendMessage(string.Empty, string.Empty);
//发送邮件
CoolInstance.Instance.SendMail(string.Empty, string.Empty);
return count;
}
///
/// 初始化订单信息
///
private void InitOrderInfo()
{
}
///
/// 新增订单信息
///
///
private int Add()
{
return 0;
}
}
~~~
这样我们就完成了短信发送服务及邮件发送服务的控制。主要还是根据自己的业务需要。
2、例如我们现在提供一个系统日志服务或者打印或者扫描的服务,我们希望全局只有一个访问入口,那么我们就可以通过这样的单例模式来实现这样的需求。
~~~
public class PrintHelper
{
#region 构造函数
private PrintHelper()
{
}
public static readonly PrintHelper Instance = new PrintHelper();
#endregion
#region 打印服务
///
/// 直接打印服务
///
///
public bool Print()
{
return true;
}
///
/// 打印预览
///
///
public bool PrintPreview()
{
return true;
}
#endregion
}
~~~
具体的调用类我就不写相应的代码,都和上面的形式类同,下面我们讲解下可能更特殊的需求,有时候我们可能需要更新我们创建的唯一实例,这时我们如何控
制单例实例对象的更新呢,有时候可能我们有这样的需求。下面我们来看看如何实现这样的需求。
3、可更新单例对象的场景
首先我们先说下什么情况下会遇到这样的更新方式呢?例如我们想在单例模式的类的构造函数是带有一定参数的情形时:
~~~
public class UpdateHelper
{
private string type = string.Empty;
private static object _lock = new object();
private static UpdateHelper instance;
private UpdateHelper(string valueType)
{
type = valueType;
}
public static UpdateHelper Instance
{
get
{
lock (_lock)
{
if (instance == null)
{
//如果这里有多个条件需求的话,可能写起来会比较复杂,那么有更好的方式来处理吗?
instance = new UpdateHelper("test!");
}
return instance;
}
}
}
}
~~~
那么我们来分析几种办法,有没有更好的办法来处理呢?
1、首先我们不能手动实例化,所以我们没有办法动态传入构造函数参数,只能在类的内部指定这个参数,但是有时候我们需要动态的更新这个参数,那么这样的
形式显然就没有办法实现。
2、通过属性的方式,来动态的设置属性的内容来完成输出参数的改变,但是这样的方式可能太过自由,无法满足单例模式的初衷。
3、接口方式,因为接口必须要靠类来实现,所以更不靠谱,可以不考虑这样的方式。
4、通过Attribute的方式来将信息动态的注入到构造函数中,但是怎么说这样的方式是不是太兴师动众了呢?毕竟单例模式本来就是很简单的。
5、通过配置文件,通过config文件配置节点的形式来动态的配置相关信息,实现更新实例对象内容的情况。
通过上面的5种情况的分析,那么通过2、4、5可以实现这个要求,但是对比相应的代价来说,5的方式是最灵活也是最符合单例模式本来的规范要求,相对来说
成本和代价也可以接收。
~~~
value
~~~
那么我们上面的单力模型中的代码只需要稍微的变化下即可,请看如下代码:
~~~
public class UpdateHelper
{
private string type = string.Empty;
private static object _lock = new object();
private static UpdateHelper instance;
private UpdateHelper(string valueType)
{
type = valueType;
}
public static UpdateHelper Instance
{
get
{
lock (_lock)
{
if (instance == null)
{
//如果这里有多个条件需求的话,可能写起来会比较复杂,那么有更好的方式来处理吗?
instance = new UpdateHelper(System.Configuration.ConfigurationManager.AppSettings["ssss"].ToString());
}
return instance;
}
}
}
}
~~~
我想到这里大家都对单例模式有个简单的认识了,本文的内容就讲到这里。我们来回顾下我们讲述的内容:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-18_5714bc35e9965.png "image")](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/0526b70f3950_F181/image_14.png)
### 六、本文总结
本文主要讲述了创建型模式中的单例模式,单例模式主要是用来控制系统中的某个类的实例的数量及全局的访问入口点。我们主要讲述了实现单例模式的方式,
分为外部方式及内部方式,当然我们现在采用的方式都是内部方式,还讲述了线程安全的单例模式及带有参数的构造函数的情况,根据配置文件来实现参数值的动态配
置的情况。希望本文的讲解能对不熟悉设计模式的同仁能够了解知道单例模式的应用,而对已熟知单例模式的同仁可以温故而知新,我会努力写好这个系列,当然我这
里可能在大牛的面前可能是班门弄斧吧,不过我会继续努力,争取写出让大家一看就明白的设计模式系列。本文错误之处再所难免,还请大家批评之处,我会继续改
进。
### 七、系列进度
##### 创建型
1、[系统架构技能之设计模式-单件模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/02/1841390.html)
2、系统架构技能之设计模式-工厂模式
3、系统架构技能之设计模式-抽象工厂模式
4、系统架构技能之设计模式-创建者模式
5、系统架构技能之设计模式-原型模式
##### 结构型
1、系统架构技能之设计模式-组合模式
2、系统架构技能之设计模式-外观模式
3、系统架构技能之设计模式-适配器模式
4、系统架构技能之设计模式-桥模式
5、系统架构技能之设计模式-装饰模式
6、系统架构技能之设计模式-享元模式
7、系统架构技能之设计模式-代理模式
##### 行为型
1、系统架构技能之设计模式-命令模式
2、系统架构技能之设计模式-观察者模式
3、系统架构技能之设计模式-策略模式
4、系统架构技能之设计模式-职责模式
5、系统架构技能之设计模式-模板模式
6、系统架构技能之设计模式-中介者模式
7、系统架构技能之设计模式-解释器模式
### 八、下篇预告
下篇我们将会介绍我们大家最熟知的工程模式,当然我会更多的结合实例来讲解每个设计模式的应用场景及具体的实例,来更清晰的描述什么情况下用什么模
式,及每个模式之间的区别。大家的支持就是我书写的动力,希望大家多多支持我吧!
';
前言
最后更新于:2022-04-01 20:25:17
> 原文出处:[系统架构师技能学习](http://blog.csdn.net/column/details/archi.html)
作者:[hegezhou](http://blog.csdn.net/hegezhou)
**本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!**
# 系统架构师技能学习
> 其实我本来不是打算把系统架构中的一些设计模式单独抽出来讲解的,因为很多的好朋友也比较关注这方面的内容,所以我想通过我理解及平时项目中应用到的一些常见的设计模式,拿出来给大家做个简单讲解,我这里只是抛砖引玉,如果某个地方讲解的不正确或者不详细,请大家批评指出。
';