之前对工厂设计模式的认知一直是:这不就是简单的i根据不同的f--else的分支,创建不同的实现类嘛,如果需要扩展,根据不同的情况再去扩展不同的实现类而已嘛,这有什么难的嘛...,想来,这样的理解倒也不能说错,只是感觉非常的假大空。
假设:我们的业务场景如下
/** * 既定业务场景: * 前情提要: * 我们需要做一个文件上传解析的功能,假设现在文件已经上传上来,我们需要对数据进行解析,将数据拆解 * * 需求: * 假设是一个目录结构,按照章节的不同,我们总共分为700章,每一章的目录结构层级都不相同。 * 例200章如下所示: * 名称:200章-架构-思想-设计模式-工厂模式 * code:200-JG-SX-SJMS-GCMS * 例100章如下所示: * 名称:100章-技术-C#-委托 * code:100-JS-C#-Delegate * * 假设用户上传的时候,只会传进来Code,我们需要根据Code获取到章节、类别。 * 现知道规则如下: * 1.所有的章节code,第一个字符为章节 * 2.200章倒数第二,第三位为类别,100章倒数第三位为类别。 */
我们现在只有一百章和二百章的数据结构和处理规则,但是领导说,我们这个东西,肯定是要把所有的章节都进行处理的。我们先来看一下不使用设计模式的处理方式
1 List<string> codeList = new List<string>(; 2 codeList.Add("200-JG-SX-SJMS-GCMS"; 3 codeList.Add("100-JS-C#-Delegate"; 4 foreach (var code in codeList 5 { 6 string Chapter = code.Split('-'[0]; 7 if (Chapter.Equals("100" 8 { 9 string chapter100 = code.Split('-'[0]; 10 string Type100 = code.Split('-'[1]; 11 Console.WriteLine($"code:{code},章节:{chapter100},类型:{Type100}"; 12 } 13 else if (Chapter.Equals("200" 14 { 15 string chapter400 = code.Split('-'[0]; 16 string Type400 = $"{code.Split('-'[2]}-{code.Split('-'[3]}"; 17 Console.WriteLine($"code:{code},章节:{chapter400},类型:{Type400}"; 18 } 19 }
处理思路是先循环集合,然后拆出来章节。根据章节去选择不同的分支。假设我们再有不同的章节,再添加elseIf就可以了。这个例子处理比较简单,代码看起来也不是很乱,但是如果我们的每一个章节的处理逻辑都比较复杂的时候,代码会乱成一团,首先不美观,其次。我们如果要新增不同的分支,在原有代码上再加分支,分支变多以后,代码会变得很长,别人会难以理解。好处是代码结构清晰,便于理解
public interface Idisassemble { /** * 拆解的接口,包含拆解的基本方法,包含获取章节和类别 */ string GetChapter(string code; string GetType(string code; } /// <summary> /// 100章截取工厂 /// </summary> public class DisassembleOneChapter : Idisassemble { public string GetChapter(string code { string Chapter= code.Split('-'[0]; return Chapter; } public string GetType(string code { string Chapter = code.Split('-'[1]; return Chapter; } } /// <summary> /// 400章的截取工厂 /// </summary> public class DisassembleTwoChapter : Idisassemble { public string GetChapter(string code { string Chapter = code.Split('-'[0]; return Chapter; } public string GetType(string code { string [] codeList= code.Split('-'; string Chapter = $"{codeList[2]}-{codeList[3]}"; return Chapter; } } public static class BuildFactory { public static Idisassemble Build(string code { Idisassemble idisassemble = null; string Chapter = code.Split('-'[0]; switch (Chapter { case "100": idisassemble = new DisassembleOneChapter(; break; case "200": idisassemble = new DisassembleTwoChapter(; break; default: break; } return idisassemble; } }
使用方式:
static void Main(string[] args { List<string> codeList = new List<string>(; codeList.Add("200-JG-SX-SJMS-GCMS"; codeList.Add("100-JS-C#-Delegate"; foreach (var code in codeList { Idisassemble idisassemble = BuildFactory.Build(code; Console.WriteLine($"code:{code},章节:{idisassemble.GetChapter(code},类型:{idisassemble.GetType(code}"; } Console.ReadLine(; }
首先工厂模式的好处是:我可以用一个通用的接口,根据业务的不同,选择不同的实现方式,这样我们不会将所有的实现都在一个方法中实现,不会出现很长的代码段。
public interface Idisassemble { /** * 拆解的接口,包含拆解的基本方法,包含获取章节和类别 */ string GetChapter(string code; string GetType(string code; }
有了这个接口以后,我们需要根据他不同的业务类型创建不同的工厂实例,分析我们的业务中目前有一百章和两百章两种不同的实现分支。所以我们对应的有一百章和两百章两个不同的实现工厂。
/// <summary> /// 100章截取工厂 /// </summary> public class DisassembleOneChapter : Idisassemble { public string GetChapter(string code { string Chapter= code.Split('-'[0]; return Chapter; } public string GetType(string code { string Chapter = code.Split('-'[1]; return Chapter; } } /// <summary> /// 400章的截取工厂 /// </summary> public class DisassembleTwoChapter : Idisassemble { public string GetChapter(string code { string Chapter = code.Split('-'[0]; return Chapter; } public string GetType(string code { string [] codeList= code.Split('-'; string Chapter = $"{codeList[2]}-{codeList[3]}"; return Chapter; } }
到这里,我们引入一个新的概念,策略模式,策略模式是在程序运行时去判断我到底需要走哪个分支。
public static class BuildFactory { public static Idisassemble Build(string code { Idisassemble idisassemble = null; string Chapter = code.Split('-'[0]; switch (Chapter { case "100": idisassemble = new DisassembleOneChapter(; break; case "200": idisassemble = new DisassembleTwoChapter(; break; default: break; } return idisassemble; } }
这个类我们需要知道用户输入什么,根据用户的不同输入,解析出来不同的分支,创建不同的实现工厂。但是我们在实际业务用的时候,最终使用的是工厂类中的某一个方法。所以,我们这个类只能是返回接口,而不是具体的实现工厂。我们在当前这个假定的业务中,可以根据code拆分出来具体使用哪个工厂。实际业务中可能会更复杂。
static void Main(string[] args { List<string> codeList = new List<string>(; codeList.Add("200-JG-SX-SJMS-GCMS"; codeList.Add("100-JS-C#-Delegate"; foreach (var code in codeList { Idisassemble idisassemble = BuildFactory.Build(code; Console.WriteLine($"code:{code},章节:{idisassemble.GetChapter(code},类型:{idisassemble.GetType(code}"; } Console.ReadLine(; }
到目前,我们的工厂创建已经完成了,但是,我们观察这两个工厂,它里面的获取章节的方法是重复的。业务简单抄一份倒也无所谓,但是如果业务复杂,抄一份的工作量还是很大的,而且从设计的角度来看,我们所有重复的,都可以抽出来。
public interface Idisassemble { /** * 拆解的接口,包含拆解的基本方法,包含获取章节和类别 */ string GetChapter(string code; string GetType(string code; } public abstract class DisassembleAbtract : Idisassemble { public string GetChapter(string code { string Chapter = code.Split('-'[0]; return Chapter; } public abstract string GetType(string code; } /// <summary> /// 100章截取工厂 /// </summary> public class DisassembleOneChapter : DisassembleAbtract { //public string GetChapter(string code //{ // string Chapter= code.Split('-'[0]; // return Chapter; //} public override string GetType(string code { string Chapter = code.Split('-'[1]; return Chapter; } } /// <summary> /// 400章的截取工厂 /// </summary> public class DisassembleTwoChapter : DisassembleAbtract { //public string GetChapter(string code //{ // string Chapter = code.Split('-'[0]; // return Chapter; //} public override string GetType(string code { string [] codeList= code.Split('-'; string Chapter = $"{codeList[2]}-{codeList[3]}"; return Chapter; } }
封装,继承,多态,虚方法。👍