Redeployment比较适合练习和再次开发,如果你想快速学习设计模式,分层开发,模块设计,重构在真实项目中的应用,同时你的学习语言是C#,那么Redeployment比较适合你
本篇文章是我设计模式实战的第一篇,我打算把这个系列写成从应用学模式,概念由别人解释去吧,如果你想知道什么是设计模式很抱歉,我只打算写应用。呵呵
第一篇设计模式在OA中的应用
项目背景:
一个煤炭行业的OA系统,现在有个新需求:人员调动,人员调动在国有企业是常见的事情,目前我们得知需要实现3种人员调动,第一是人员岗位调动(转岗),第二人员部门调动,第三人员企业调动(国企是可以出现夸企业高层管理人员调动的),目前人员调动和部门调动企业内部可以决定,但是人员企业调动是需要上级领导部门审批。做过OA的朋友知道里面充斥的权限的问题,因此人员调动如果设计的不合理,加上权限将会给日后维护带来困难。
分析和解决:
首先找出这里的变化:调动的种类和调动信息的状态。也许还有其他的。遇到变化我们应该尝试封装,首先让我们对第一个变化做封装,看下图。

第二个变化的状态怎么封装呢?我想起自己学的状态模式(如果你还不了解状态模式请先翻阅相关资料),突然感觉是该用的时候了,查看状态模式的时候看到有人谈到状态模式和策略模式,策略模式是封装算法的变化,aha!我对第一个人员调动变化的封装不就是策略模式么?不过好像缺少一个控制对象(暂时不考虑这个)。
虽然解决了两个变化但是总感觉两者关系松散,碰到两个变化我们应该首先想到聚合不是继承,因此我觉得把第二个变化聚合到第一个内部。如图:

pedeploy腰身一变成了state的控制类,晕怎么越看越像桥接模式!!(我只能说左边的是策略模式,右边的是的状态模式,具体在一起是不是桥接模式读者有心自己去研究吧,我就不误人子弟了),而我们现在Redeploy他的控制对象呢?现在我们碰到了如何产生调动对象的问题了,ok你发现了我们应该使用工厂方法,我打算用工厂来封装调动对象实例化的变化。还是看图:
设计总结:
ok到现在整个设计完成了。总结一下首先我们因为封装变化无疑发现在使用策略模式,这也是《设计模式解析2版》说的模式可以通过原则推出来,第二模式可以组合。
那么我们来看看我们这个设计的灵活性,如果想添加新的调动情况,比如添加岗位+部门一起调动,那么我们可以在新添加一个Pedeploy的子类,然后工厂里面添加对应的语句,如果现在岗位调动需要某某检查部门审批,你现在需要做的是给state新添加子类,然后让岗位调动拥有这个新状态机制。
想看代码?ok!
代码:
工厂部分:

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
5
namespace Redeployment
6

{
7
//工厂方法产生异动策略模式对象
8
public class RedeployFactory
9
{
10
public static RedeployStrategy GetRedeploy(string redeployKind,RedeployInfor rpinfo)
11
{
12
switch (redeployKind)
13
{
14
case "gangwei":
15
return new StationRedeployStrategy(rpinfo);
16
case "kequ":
17
return new DepartmentRedeployStrategy(rpinfo);
18
case "danwei":
19
return new CorporationRedeployStrategy(rpinfo);
20
default:
21
return null;
22
}
23
}
24
}
25
26
//异动信息
27
public class RedeployInfor
28
{
29
//身份号
30
public string ID;
31
32
//申请日期
33
public DateTime applyTime;
34
35
//申请单位
36
public string applyDepartment;
37
38
//目标值(调动的目标)
39
public string tarGet;
40
41
//备注
42
public string beiZhu;
43
44
//当前异动状态
45
public State state = null;
46
public RedeployInfor(string id, DateTime applytime, string applydepartment, string target, string beizhu, StateType stateType)
47
{
48
this.ID = id;
49
this.applyTime = applytime;
50
this.applyDepartment = applydepartment;
51
this.beiZhu = beizhu;
52
this.tarGet = target;
53
54
switch (stateType)
55
{
56
case StateType.Apply:
57
state = new ApplyState();
58
break;
59
case StateType.Wait:
60
state = new ApplyState();
61
break;
62
case StateType.Pass:
63
state = new PassState();
64
break;
65
case StateType.NoPass:
66
state = new NoPassState();
67
break;
68
default:
69
state = new ApplyState();
70
break;
71
}
72
}
73
}
74
75
//枚举状态
76
public enum StateType
77
{
78
/**//// <summary>
79
/// 申请
80
/// </summary>
81
Apply,
82
83
/**//// <summary>
84
/// 待审批
85
/// </summary>
86
Wait,
87
88
/**//// <summary>
89
/// 审批通过
90
/// </summary>
91
Pass,
92
93
/**//// <summary>
94
/// 审批未通过
95
/// </summary>
96
NoPass
97
}
98
}
99
调动策略模块:
* RedeployStrategy(调动抽象类):

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
namespace Redeployment
5

{
6
//策略模式管理异动的算法
7
public abstract class RedeployStrategy
8
{
9
//异动信息
10
protected RedeployInfor rpInfo;
11
12
//构造方法
13
public RedeployStrategy(RedeployInfor rpinfo)
14
{
15
rpInfo = rpinfo;
16
}
17
18
状态转换方法#region 状态转换方法
19
public void setState(State state)
20
{
21
rpInfo.state = state;
22
}
23
24
public void Pass()
25
{
26
rpInfo.state.Pass(this);
27
}
28
29
public void NoPass()
30
{
31
rpInfo.state.NoPass(this);
32
}
33
#endregion
34
35
//抽象方法异动的工作开始
36
public virtual void RedeployWorking()
37
{
38
39
}
40
41
}
42
43
}
44
* StationRedeployStrategy(岗位调动类):

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
5
namespace Redeployment
6

{
7
public class StationRedeployStrategy : RedeployStrategy
8
{
9
public StationRedeployStrategy(RedeployInfor rpinfo)
10
: base(rpinfo)
11
{
12
13
}
14
public override void RedeployWorking()
15
{
16
if (true)//点击的是Okbutton(注意okbutton意思是审批通过点击了)
17
{
18
//审批通过了
19
this.Pass();
20
21
//此地通过读取当前状态
22
string statenow = rpInfo.state.GetState();
23
24
//下面statenow配合rpInfo中的,身份号,申请日期,申请单位,备注写入数据库,目标值,和异动类型为更换岗位(注意这点)
25
//写sql
26
}
27
else
28
{
29
//审批不通过了
30
this.NoPass();
31
32
//此地通过读取当前状态
33
string statenow = this.rpInfo.state.GetState();
34
35
//下面statenow配合rpInfo中的,身份号,申请日期,申请单位,备注写入数据库,目标值,和异动类型为更换岗位(注意这点)
36
//写sql
37
}
38
}
39
}
40
}
41
其他两个调度雷同如需要可下载代码。
调动状态模块:
* State(状态抽象类):

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
5
namespace Redeployment
6

{
7
//状态模式管理流的状态
8
public abstract class State
9
{
10
public abstract void Pass(RedeployStrategy c);
11
public abstract void NoPass(RedeployStrategy c);
12
public abstract string GetState();
13
}
14
}
15
* ApplyState(申请状态)

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
5
namespace Redeployment
6

{
7
public class ApplyState : State
8
{
9
//申请通过后改变自身状态到PassState
10
public override void Pass(RedeployStrategy c)
11
{
12
c.setState(new PassState());
13
}
14
15
//申请不通过后改变自身状态到NoPassState
16
public override void NoPass(RedeployStrategy c)
17
{
18
c.setState(new NoPassState());
19
}
20
21
//获取当前状态
22
public override string GetState()
23
{
24
return "待审批";
25
}
26
}
27
}
28
其他两个状态类代码请下载源码查看。
大家注意到了RedeployFactory.cs文件内定义了RedeployInfor(调动信息),这里这个类是我后来添加的,如果不添加
RedeployInfor那么调动对象的构造方法将会出现很多参数,这么重构的好处是把变化用一个类封装了,现在RedeployInfor相对稳定,调动对象的构造方法就不用因为调动信息的改变该来该去。
遗留问题:
如果调动人员很多,那么调动对象会很多,如何实现调动对象共用,我曾想过用单件模式,未果,请高手指导。
代码下载:
注:.net2.0开发
yatasoft
相关文章
Redeployment——应用
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!