如何解决重构对象列表以实现业务规则
| 我需要重构以下类:public interface IEmployee
{
int VacationWeeks { get; }
int YearsWithCompany { set; get; }
double Salary { set; get; }
}
public class Employee : IEmployee
{
private readonly int vacationWeeks;
public Employee(int vacationWeeks)
{
this.vacationWeeks = vacationWeeks;
}
public int VacationWeeks
{
get { return vacationWeeks; }
}
public int YearsWithCompany { set; get; }
public double Salary { set; get; }
}
我需要确保VacationWeeks仅取决于YearsWithCompany,并且正在从数据库加载映射。到目前为止,我已经提出了:
public class EmployeeNew : IEmployee
{
private Dictionary<int,int> vacationWeeksTable;
public EmployeeNew(Dictionary<int,int> vacationWeeksTable)
{
this.vacationWeeksTable = vacationWeeksTable;
}
public int VacationWeeks
{
get { return vacationWeeksTable[YearsWithCompany]; }
}
public int YearsWithCompany { set; get; }
public double Salary { set; get; }
}
此类实现了我想要的功能,但仍然存在一个漏洞:可能已使用VacationWeeksTable的不同实例创建了同一集合中EmployeeNew的不同实例。
同一集合中EmployeeNew的所有实例必须引用相同的VacationWeeksTable。
我重构的应用程序在整个系统中使用了很多List,我们需要能够修改YearsWithCompany和Salary,但要保证每个List仅使用一个VacationWeeksTable。这些列表被迭代了几次;它的元素在每次迭代中都会修改。
这是我不完善的解决方案。欢迎提出建议:
// this class does two things,which I do not like
public class EmployeeList : IEnumerable<IEmployee>,IEmployee
{
private Dictionary<int,int> vacationWeeksTable;
private List<EmployeeSpecificData> employees;
private int currentIndex;
private EmployeeSpecificData CurrentEmployee
{
get { return employees[currentIndex]; }
}
public IEnumerator<IEmployee> GetEnumerator()
{
for (currentIndex = 0; currentIndex < employees.Count; currentIndex++)
{
yield return this;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int VacationWeeks
{
get { return vacationWeeksTable[YearsWithCompany]; }
}
// this is ugly repetitive code I don\'t like
public int YearsWithCompany
{
get { return CurrentEmployee.YearsWithCompany; }
set { CurrentEmployee.YearsWithCompany = value; }
}
// this is ugly repetitive code I don\'t like
public double Salary
{
get { return CurrentEmployee.Salary; }
set { CurrentEmployee.Salary = value; }
}
}
解决方法
我使用以下代码创建和初始化一些需要默认行为和共享行为的类。也许您可以重构它会有所帮助:
它是Factory和FlyWeight模式组合的某种形式(可以在您的方案中删除flyweight部分),此外还有类Type共享处理程序的概念。
我简化并删除了一些您不需要的东西,但还有更多要删除的地方,我添加了评论。
用法为:(应用初始化)
Dictionary<int,int> vacationWeeksTable = new Dictionary<int,int>();
// fill the table
Factory<Employee>.Init(vacationWeeksTable);
每当您创建Employee类时:
// remove grouping in the factory class to remove this null
Employee em = Factory<Employee>.Create(null);
它仅对类使用WeakReference,因此您不必担心GC。
每位员工将在创建时拥有共享的VacationWeeksTable设置,如果不使用工厂类,则无法从外部进行更改。
您可以在应用程序的运行时随时更改Employee所有正在运行的实例的假期表,方法是:
// this will call the method registered for SetInitialdata on all instances of Employee classes.
// again remove grouping to remove that null
Factory<Employee>.Call(EventHandlerTypes.SetInitialData,null,vacTable);
员工实施示例:
class Employee : IBaseClass
{
private Dictionary<int,int> vacationWeeksTable;
public virtual void RegisterSharedHandlers(int? group,Action<IKey,int?,EventHandlerTypes,Action<object,SharedEventArgs>> register)
{
group = 0; // disable different groups
register(new Key<Employee,int>(0),group,EventHandlerTypes.SetInitialData,SetVacationWeeksTable);
}
public virtual void RegisterSharedData(Action<IKey,object> regData)
{
// remove this from factory and interface,you probably dont need it
// I have been using it as a FlyWeight data store for classes.
}
private void SetVacationWeeksTable(object sender,SharedEventArgs e)
{
vacationWeeksTable = e.GetData<Dictionary<int,int>>();
}
}
代码模式实现:
IBaseClass:我可以通过工厂实现创建的每个类的接口
public enum EventHandlerTypes
{
SetInitialData // you can add additional shared handlers here and Factory<C>.Call - it.
}
public class SharedEventArgs : EventArgs
{
private object data;
public SharedEventArgs(object data)
{
this.data = data;
}
public T GetData<T>()
{
return (T)data;
}
}
public interface IBaseClass
{
void RegisterSharedHandlers(int? group,SharedEventArgs>> regEvent);
void RegisterSharedData(Action<IKey,object> regData);
}
实用程序通用类:
public interface IKey
{
Type GetKeyType();
V GetValue<V>();
}
public class Key<T,V> : IKey
{
public V ID { get; set; }
public Key(V id)
{
ID = id;
}
public Type GetKeyType()
{
return typeof(T);
}
public Tp GetValue<Tp>()
{
return (Tp)(object)ID;
}
}
public class Triple<T,V,Z>
{
public T First { get; set; }
public V Second { get; set; }
public Z Third { get; set; }
public Triple(T first,V second,Z third)
{
First = first;
Second = second;
Third = third;
}
}
工厂类进行了一些修改以处理您的情况:
public static class Factory<C> where C : IBaseClass,new()
{
private static object initialData;
private static Dictionary<IKey,Triple<EventHandlerTypes,int,WeakReference>> handlers = new Dictionary<IKey,WeakReference>>();
private static Dictionary<IKey,object> data = new Dictionary<IKey,object>();
static Factory()
{
C newClass = new C();
newClass.RegisterSharedData(registerSharedData);
}
public static void Init<IT>(IT initData)
{
initialData = initData;
}
public static Dt[] GetData<Dt>()
{
var dataList = from d in data where d.Key.GetKeyType() == typeof(Dt) select d.Value;
return dataList.Cast<Dt>().ToArray();
}
private static void registerSharedData(IKey key,object value)
{
data.Add(key,value);
}
public static C Create(int? group)
{
C newClass = new C();
newClass.RegisterSharedHandlers(group,registerSharedHandlers);
// this is a bit bad here since it will call it on all instances
// it would be better if you can call this from outside after creating all the classes
Factory<C>.Call(EventHandlerTypes.SetInitialData,initialData);
return newClass;
}
private static void registerSharedHandlers(IKey subscriber,int? group,EventHandlerTypes type,SharedEventArgs> handler)
{
handlers.Add(subscriber,new Triple<EventHandlerTypes,WeakReference>(type,group ?? -1,new WeakReference(handler)));
}
public static void Call<N>(EventHandlerTypes type,N data)
{
Call<N>(null,type,data);
}
public static void Call<N>(object sender,N data)
{
lock (handlers)
{
var invalid = from h in handlers where h.Value.Third.Target == null select h.Key;
// delete expired references
foreach (var inv in invalid.ToList()) handlers.Remove(inv);
var events = from h in handlers where h.Value.First == type && (!@group.HasValue || h.Value.Second == (int)@group) select h.Value.Third;
foreach (var ev in events.ToList())
{
// call the handler
((Action<object,SharedEventArgs>)ev.Target)(sender,arg);
}
}
}
}
, 制作一个包含Dictionary的类。创建或获取此新类的实例将以一致的方式加载字典。然后,您的BO可以使用该类的一个实例,从而确保它们都使用相同的数据(因为包含列表的类知道如何使用适当的数据集进行自身加载)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。