必会重构技巧(一):封装集合
封装集合:将集合中的某些方法封装起来,这些方法一般会牵扯到其他的逻辑。
举例理解:比如你给一个List<T>里面加一个对象的同时,可能还有一个计数器在计算List中对象的个数,我们不用暴露计数器,这样List.Add()和List.Remove()我们就可以封装起来了。
项目实例:我记得我有个项目需要不断的从数据库中读取User的Guid然后狂发Mail。开始的想法很简单,根据Window ID 去 CorpDirectory 抓Guid和Mail Address就好了。实际情况也就这么简单,但是后来Debug的时候发现程序很慢,弄了半天终于发现是这个抓Guid和Mail的动作太慢了,CorpDirectory 这个DB在美国,Production的Server在国内,于是乎每次请求都来往返于太平洋。怎么解决?大家肯定一个就想到了Cache,恩,我第一个也是想到了在Server创建Cache。本实例的意义并不在于使用Cache来提高App的性能,而在于对于Cache内对象的存取。
先来看看原始的未经过封装的代码:
public class UserEntity
{
public Guid Gid { get; set; }
public string Name { get; set; }
}

private void OldAddUserCache()
{
var user = new UserEntity
{
Gid = new Guid(),
Name = "Yang,Dennis"
};
IDictionary<Guid, string> users = new Dictionary<Guid, string>();
if (Cache["Users>"] != null)
{
users = Cache["Users"] as IDictionary<Guid, string>;
if (users != null && !users.ContainsKey(user.Gid))
{
users.Add(user.Gid, user.Name);
Cache["Users"] = users;
}
}
else
{
Cache["Users"] = users;
}
}
以上方法可以实现对Cache的添加,让我们分析一下有什么问题,我觉得至少有以下四点:
public enum ManageUserCacheActionType
{
Add = 1,
Remove = 2,
Read = 3
}
private void TestManagerUserCache()
{
var user = new UserEntity
{
Gid = new Guid(),
Name = "Yang,Dennis"
};
ManageUserCache(user, ManageUserCacheActionType.Add);
ManageUserCache(user, ManageUserCacheActionType.Read);
ManageUserCache(user, ManageUserCacheActionType.Remove);
ManageUserCache(user, ManageUserCacheActionType.Read);
}

private void ManageUserCache(UserEntity user, ManageUserCacheActionType act)
{
IDictionary<Guid, string> users = new Dictionary<Guid, string>();
if (Cache["Users"] != null)
{
users = Cache["Users"] as IDictionary<Guid, string>;
switch (act.ToString())
{
case "Add":
ManageUserCacheAdd(users, user);
break;
case "Remove":
ManageUserCacheRemove(users, user);
break;
case "Read":
ManageUserCacheRead(users, user);
break;
default:
return;
}
}
else
{
Cache["Users"] = users;
}
}

private void ManageUserCache(UserEntity user, ManageUserCacheActionType act)
{
IDictionary<Guid, string> users = new Dictionary<Guid, string>();
if (Cache["Users"] != null)
{
users = Cache["Users"] as IDictionary<Guid, string>;
switch (act.ToString())
{
case "Add":
ManageUserCacheAdd(users, user);
break;
case "Remove":
ManageUserCacheRemove(users, user);
break;
case "Read":
ManageUserCacheRead(users, user);
break;
default:
return;
}
}
else
{
Cache["Users"] = users;
}
}

private void ManageUserCacheRead(IDictionary<Guid, string> users, UserEntity user)
{
if (users != null && users.ContainsKey(user.Gid))
{
Response.Write(string.Format("Guid:{0} -- Name:{1}<br>", user.Gid, user.Name));
}
else
{
Response.Write(string.Format("Guid:{0} not exist<br>", user.Gid));
}
}
private void ManageUserCacheRemove(IDictionary<Guid, string> users, UserEntity user)
{
if (users != null && users.ContainsKey(user.Gid))
{
users.Remove(user.Gid);
Cache["Users"] = users;
}
}
private void ManageUserCacheAdd(IDictionary<Guid, string> users, UserEntity user)
{
if (users != null && !users.ContainsKey(user.Gid))
{
users.Add(user.Gid, user.Name);
Cache["Users"] = users;
}
}
以上重构方法包括:对集合方法的封装;提取方法;功能的单一化。
归纳总结:
(1)把易出Bug的方法封装到类中,不要直接暴露出来,比如对于List,Dictionary,Queue等的Add(),Remove()。
(2)在本文中其实也用到了其它的重构方法,如提取方法,提取方法对象,后面会有专门一篇介绍提取的技巧。
OK,这下清晰了,除了主函数,其它的方法可以独立出一个UserCacheUtility的类文件,以后所有对于UserCache的操作可就相当轻松了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库