Java重构面向过程代码_如何重构代码-简单、灵活的实现对象复制

前两篇(思路和方法、重构计划)从大的方面上谈了关于重构的话题,这次从小的代码上来看。我们来看下一个的代码如何从简单到复杂,然后重构这些代码。

单个对象复制

在初步的需求中有个很简单的业务,就是定义销售合同,并且合同中可以配置产品设备数据,如下:

4ad5ac4ec316c010646a48f72162821d.png

其中有个业务功能就是需要对已经存在的销售合同进行复制、剪贴和粘贴的工作。

对于程序来说,它其实就需要实现IClone接口就可以了,

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png代码

//复制///publicobjectClone()

{

TestObj copiedObj=newTestObj();

copiedObj.Parent=null;

copiedObj.Name=this.Name;foreach(TestObj objinthis.Child)

{

TestObj childCopiedObj=obj.Clone()asTestObj;

childCopiedObj.Parent=copiedObj;

copiedObj.Child.Add(childCopiedObj);

}returncopiedObj;

}

OK,这很好的实现了业务需求。

批量复制不同对象

业务需求发生了变化,现在对于前期简单的销售合同进行了完善,同时让它变得异常复杂,如下图,

cd206c560c6be05c1b907290755b9e90.png

现在要求在所有内部对象都支持复制、剪贴和粘贴,并且也要支持每个部分的数据可以独立导出为特殊的文件,作为数据模板,对于其他合同为了简化操作可以将该模块导入,这些动作在实现前都必须要执行复制,前面的动作不用说都可以理解,对于后面的导入和导出来说,虽然主要通过序列化来支持,但是由于业务特殊性也必须先做复制操作,然后需要对复制后的数据做特殊处理,然后才去序列化。

对于这次的需求来说,很多人的实现方式是对每个类都模仿Clone的方式来写自己的复制方法,这种方式一定是正确的,并且性能是最好的,不过它也是代码量最多的,同时随着业务的进一步完善,它的代码会越来越多。

按照上述的方式来实现,可能需要两周左右的时间,可以想想有没有办法减少开发时间呢?而且也让以后的开发时间减少?

想了很久,终于有了一种思路:

b8815d39c345d5ac72a050e1badf277c.png

具体的实现代码看下这三个类的代码,

1、最核心的类CopyContainer

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png代码

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Reflection;namespaceKevin.CommonFunction.Clone

{//复制元素的容器/执行批量的复制,默认只复制对象的值类型,引用关系保留///publicclassCopyContainer

{#region属性//上下文环境参数///privateDictionarymContextParams;//等待被复制的对象///privateListmWaitToCopiedItems=newList();//被复制对象-新对象的索引关系///privateDictionarymItemIndexs=newDictionary();//构造函数的缓存///privateDictionarymConstcCache=newDictionary();//字段的缓存///privateDictionary>mFieldInfoCache=newDictionary>();//复制后的新对象///privateListmNewItems=newList();#endregion#region构造函数/publicCopyContainer()

{

}#endregion#region方法//添加等待被复制的对象//需要复制的对象publicvoidAddToWaitCopiedItems(objectwaitCopiedItem)

{if(waitCopiedItem!=null&&!mWaitToCopiedItems.Contains(waitCopiedItem))

{this.mWaitToCopiedItems.Add(waitCopiedItem);

}

}//添加环境参数//环境中的唯一主键///环境参数publicvoidAddToContextParams(stringkey,objectcontextParam)

{if(mContextParams==null)

{

mContextParams=newDictionary();

}this.mContextParams.Add(key, contextParam);

}//复制对象//所有复制后的对象列表publicListClone()

{if(this.mWaitToCopiedItems==null)

{returnnull;

}foreach(objectobjinthis.mWaitToCopiedItems)

{objectnewObj=CopyToNewObj(obj);

mItemIndexs.Add(obj, newObj);

mNewItems.Add(newObj);

}foreach(objectnewObjinmNewItems)

{

ICopyReference copiedObj=newObjasICopyReference;if(copiedObj!=null)

{

copiedObj.SetReference(this.mContextParams,this.mItemIndexs);

}

}returnthis.mNewItems;

}//复制对象//被复制的对象///复制后的对象privateobjectCopyToNewObj(objectcopeidItem)

{

Type copiedType=copeidItem.GetType();

ConstructorInfo constc=this.GetConstructor(copiedType);

Listfields=this.GetFieldInfos(copiedType);objectnewObj=constc.Invoke(null);foreach(FieldInfo fieldinfields)

{objectcopiedValue=field.GetValue(copeidItem);

field.SetValue(newObj, copiedValue);

}returnnewObj;

}//获取构造函数//被复制对象的类型///构造函数privateConstructorInfo GetConstructor(Type copiedType)

{

ConstructorInfo copiedConstc=null;if(this.mConstcCache.ContainsKey(copiedType))

{

copiedConstc=this.mConstcCache[copiedType];

}//该构造函数未加入缓存else{

ConstructorInfo[] constructors=copiedType.GetConstructors(BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Public);//循环所有构造函数foreach(ConstructorInfo constcinconstructors)

{

ParameterInfo[] paramsInConst=constc.GetParameters();if(paramsInConst.Length==0)

{

copiedConstc=constc;break;

}

}if(copiedConstc==null)

{thrownewException(string.Format("类 '{0}' 缺少无参的构造函数", copiedType.FullName));

}this.mConstcCache.Add(copiedType, copiedConstc);

}returncopiedConstc;

}//获取字段//被复制对象的字段///字段privateListGetFieldInfos(Type copiedType)

{

Listfields=null;if(this.mFieldInfoCache.ContainsKey(copiedType))

{

fields=this.mFieldInfoCache[copiedType];

}//该字段未加入缓存else{

fields=newList();

FieldInfo[] fieldsInCT=copiedType.GetFields(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance);foreach(FieldInfo fieldIteminfieldsInCT)

{//过滤带有KeepFixedValueAttribute自定义属性的字段if(fieldItem.GetCustomAttributes(typeof(KeepFixedValueAttribute),true).Length==0)

{

fields.Add(fieldItem);

}

}this.mFieldInfoCache.Add(copiedType, fields);

}returnfields;

}#endregion}

}

2、复制对象引用的操作接口ICopyReference

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png代码

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;namespaceKevin.CommonFunction

{//复制对象引用的操作接口/当在CopyContainer中执行复制的时候,对于复制对象引用的支持//publicinterfaceICopyReference

{//设置复制对象的引用关系//上下文环境参数///被复制对象-新对象的索引关系voidSetReference(DictionarycontextParams, DictionarymItemIndexs);

}

}

3、用于该复制操作的自定义属性KeepFixedValueAttribute

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png代码

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;namespaceKevin.CommonFunction.Clone

{//当在CopyContainer中执行复制的时候,保留对象特定字段的初始值///publicclassKeepFixedValueAttribute : Attribute

{

}

}

上述是所有的实现代码,下面看下是如何使用的:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png代码

usingSystem;usingSystem.Text;usingSystem.Collections.Generic;usingSystem.Linq;usingMicrosoft.VisualStudio.TestTools.UnitTesting;usingKevin.CommonFunction.Clone;usingKevin.CommonFunction;namespaceKevin.NUnitTest.Clone

{

[TestClass]publicclassT_CopyContainer

{

[TestMethod]publicvoidClone()

{

CopyContainer cc=newCopyContainer();

TestObj oldObj=newTestObj();

cc.AddToWaitCopiedItems(oldObj);

ListnewItems=cc.Clone();

Assert.AreEqual(newItems.Count,2);

}

}publicclassTestObj : ICopyReference

{//自动生成的主键///publicintmKey=System.Guid.NewGuid().GetHashCode();//上级对象///publicTestObj Parent;//下级对象列表///publicListChild=newList();//名称///publicstringName;//设置复制对象的引用关系//上下文环境参数///被复制对象-新对象的索引关系publicvoidSetReference(DictionarycontextParams, DictionarymItemIndexs)

{

ListarrCopiedItems=newList();foreach(TestObj objinthis.Child)

{if(mItemIndexs.ContainsKey(obj))

{

arrCopiedItems.Add(mItemIndexs[obj]);

}else{

arrCopiedItems.Add(obj);

}

}

}

}

}

虽然,每个支持复制操作的对象都需要实现ICopyReference接口,这是为了处理对象内的引用属性。但是整体而言,代码简单和清晰了很多。

其实,该操作还有其他更好的优化方式可以实现,这里只是借这个例子来说明两点:

1、写代码的时候不要因为前人怎么写,你也去模仿怎么写,这样会让你变得思维方式固化,一定要有新意,养成这种思维的习惯,并且合理地去实现它。

2、善于从不同的事物中去发现共同点,并将这个共同点抽象出来,从而达到代码复用的目的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值