C#中借助设计模式简化重复代码的技术实现问询
解决代码重复:用委托或策略模式实现通用逻辑
嘿,针对你现在的代码重复问题,其实咱们可以用委托或者策略模式来搞定,其中委托的方式更轻量直接,先给你看具体实现:
首先,整理你的现有代码(方便对照)
抽象类与子类
public abstract class Base { public int ID { get; set; } public string Countries {get;set;} } public class ClassA : Base { public string City { get;set; } } public class ClassB : Base { public string Village{ get;set; } } public class ComponentClass { public List<ClassA> classAObj { get; set; } public List<ClassB> classBObj { get; set; } } // 业务对象类 public class Parent { public List<Star> Curves { get; set; } = new List<Star>(); } public class Star { public string Area { get; set; } public string Color { get; set; } public List<TinyStar> Values { get; set; } = new List<TinyStar>(); } public class TinyStar { public string smallD { get; set; } }
原重复逻辑(已修正小问题)
Main() { ComponentClass[] c = /* Data from 3rd party */; foreach(var data in c) { Parent p = new Parent(); if(data.classAObj.Count > 0) { Star s = new Star(); s.Area = "infinite"; s.Color = "red"; List<string> sep = data.classAObj.SelectMany(a => a.City.Split(',')).ToList(); foreach(var b in sep) { TinyStar t = new TinyStar(); t.smallD = b; s.Values.Add(t); } p.Curves.Add(s); } if(data.classBObj.Count > 0) { Star s2 = new Star(); s2.Area = "infinite"; s2.Color = "red"; List<string> sep = data.classBObj.SelectMany(b => b.Village.Split(',')).ToList(); foreach(var b in sep) { TinyStar t = new TinyStar(); t.smallD = b; s2.Values.Add(t); } p.Curves.Add(s2); } } }
注:原代码里有个小错误,data.City应该是遍历classAObj里的每个对象取City属性,我这里先修正了,不然会编译报错~
方案1:用委托实现通用方法(最简洁)
我们可以把“获取分隔字符串”的逻辑作为委托参数传给通用方法,这样通用方法只需要专注于重复的逻辑,不用关心具体取哪个属性:
定义通用方法
// 通用方法:处理单个Base对象集合,以及对应的属性获取逻辑 public void ProcessItems<T>(List<T> items, Parent parent, Func<T, string> getSeparatorString) where T : Base { if(items?.Count > 0) { Star star = new Star { Area = "infinite", Color = "red" }; // 提取所有分隔后的字符串 var allParts = items.SelectMany(item => getSeparatorString(item).Split(',')); foreach(var part in allParts) { star.Values.Add(new TinyStar { smallD = part }); } parent.Curves.Add(star); } }
在Main里调用通用方法
Main() { ComponentClass[] c = /* Data from 3rd party */; foreach(var data in c) { Parent p = new Parent(); // 处理ClassA集合,传入获取City的委托 ProcessItems(data.classAObj, p, a => a.City); // 处理ClassB集合,传入获取Village的委托 ProcessItems(data.classBObj, p, b => b.Village); } }
这样一来,原来两段重复的逻辑就完全合并了,后续如果有新的子类(比如ClassC,有Town属性),只需要加一行ProcessItems(data.classCObj, p, c => c.Town)就行,非常灵活。
方案2:用策略模式(更适合复杂场景)
如果后续的逻辑会变得更复杂,比如除了获取属性还有其他差异操作,那策略模式会更合适:
定义策略接口
public interface IItemProcessor { void Process(List<Base> items, Parent parent); } // ClassA对应的策略实现 public class ClassAProcessor : IItemProcessor { public void Process(List<Base> items, Parent parent) { var classAItems = items.Cast<ClassA>().ToList(); if(classAItems.Count == 0) return; Star star = new Star { Area = "infinite", Color = "red" }; var allCities = classAItems.SelectMany(a => a.City.Split(',')); foreach(var city in allCities) { star.Values.Add(new TinyStar { smallD = city }); } parent.Curves.Add(star); } } // ClassB对应的策略实现 public class ClassBProcessor : IItemProcessor { public void Process(List<Base> items, Parent parent) { var classBItems = items.Cast<ClassB>().ToList(); if(classBItems.Count == 0) return; Star star = new Star { Area = "infinite", Color = "red" }; var allVillages = classBItems.SelectMany(b => b.Village.Split(',')); foreach(var village in allVillages) { star.Values.Add(new TinyStar { smallD = village }); } parent.Curves.Add(star); } }
定义通用处理方法
public void CommonMethod(List<Base> items, Parent parent, IItemProcessor processor) { processor.Process(items, parent); }
在Main里调用
Main() { ComponentClass[] c = /* Data from 3rd party */; foreach(var data in c) { Parent p = new Parent(); // 处理ClassA CommonMethod(data.classAObj.Cast<Base>().ToList(), p, new ClassAProcessor()); // 处理ClassB CommonMethod(data.classBObj.Cast<Base>().ToList(), p, new ClassBProcessor()); } }
这种方式的好处是,每个子类的处理逻辑都封装在单独的策略类里,后续修改或扩展时不会影响其他逻辑,适合业务逻辑比较复杂的场景。
总结
- 如果只是简单的属性差异,委托方案更简洁高效,代码量更少;
- 如果后续有更多差异化的业务逻辑,策略模式更符合开闭原则,扩展性更好。
内容的提问来源于stack exchange,提问作者user1400915
相关产品推荐
相关产品推荐

