学习设计模式《六》——抽象工厂方法模式
一、基础概念
抽象工厂模式的本质是【选择产品簇(系列)的实现】;
抽象工厂模式定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类;
抽象工厂模式功能:抽象工厂的功能是为一系列相关对象或相互依赖对象创建一个接口【抽象工厂其实是一个产品簇(系列)】【特别注意:这个接口内的方法不是任意堆砌的,而是一系列相关或相互依赖的方法】;
抽象工厂通常实现为接口;
切换产品簇(系列):由于抽象工厂定义的一系列对象通常是相关或相互依赖的,这些产品构成来了一个系列或产品簇; 这就带来了很大的灵活性,即切换一个产品簇的时候,只要提供不同的抽象工厂实现就可以。
序号 | 抽象工厂方法模式优点 | 抽象工厂方法模式缺点 |
1 | 分离接口和实现 (客户端使用抽象工厂来创建需要的对象,而客户端根本不知道具体的实现是谁,客户端只是面向产品的接口编程而已) | 不太容易扩展新的产品 (典型的抽象工厂方法若需要给整个产品新添加一个产品,那就需要修改抽象工厂,这样会导致修改所有的工厂实现类;可扩展的抽象工厂可以解决新增产品问题,但是又不够安全) |
2 | 使得切换产品系列变得容易 (因为一个具体的工厂实现代表一个产品系列【如:Schema1代表装机方案一:Intel的CPU+技嘉的主板; | 容易造成类层次复杂 (在使用抽象工厂模式时,若需要选择的层次过多,那么会造成整个类层次变得复杂) |
何时选用抽象工厂模式?
1、如果希望一个系统独立于它的产品创建、组合和表示的时候【即:希望一个系统只知道产品的接口,而不关心实现】;
2、如果一个系统要由多个产品系列中的一个来配置的时候【即:可以动态的切换多个产品簇(系列)】;
3、如果要强调一系列相关产品的接口,以便联合使用它们的时候。
二、抽象工厂方法模式示例
业务需求:比如我们需要组装电脑,在组装前我们需要选择一系列相关的配件(如:CPU、主板、内存条、硬盘、电源、机箱、音箱、键盘、鼠标、显示器等);但是我们在选择这些配件的时候会面临一系列的问题(如:品牌、型号、频率等问题确定);其次在最终确定装机方案之前,还需要考虑各个配件的兼容性(如CPU的针脚与主板的插槽数量是否匹配、购买的硬盘与主板接口是否匹配等,否则就会导致无法组装)【也就是说:装机方案是一个整体,方案里面的各个配件是相互关联的】;用户选好装机方案与配件后,给到装机工程师进行组装(即:装机工程师只是按照客户的装机方案去获取相应配件进行组装)。
为了说明抽象工厂方法,我们以下的内容简单的以组装电脑所需的CPU与主板为例进行示意说明:
2.1、不用任何设计模式的示例
1、定义CPU的接口,约束对应的功能内容
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern
{/// <summary>/// CPU接口/// </summary>internal interface ICPU{//CPU具有运算功能void Calculate();}//Interface_end
}
2、编写CPU的具体产品实现(如:Intel与AMD)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern
{/// <summary>/// Intel的CPU/// </summary>internal class IntelCPU : ICPU{private int pins = 1151;public IntelCPU(){}public IntelCPU(int pins){this.pins = pins;}public void Calculate(){Console.WriteLine($"Intel的CPU,针脚数为【{pins}】");}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern
{internal class AmdCPU : ICPU{private int pins = 940;public AmdCPU(){}public AmdCPU(int pins){this.pins = pins;}public void Calculate(){Console.WriteLine($"AMD的CPU,针脚数为【{pins}】");}}//Class_end
}
3、定义主板的接口,约束对应的功能内容
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern
{/// <summary>/// 主板接口/// </summary>internal interface IMainboard{//可安装CPU功能void InstallCPU();}//Interface_end
}
4、编写主板产品的具体实现 (如:技嘉与微星主板)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern
{internal class GAMainboard : IMainboard{private int cpuHoles = 940;public GAMainboard(){}public GAMainboard(int cpuHoles){this.cpuHoles = cpuHoles; }public void InstallCPU(){Console.WriteLine($"技嘉主板,主板插槽数为【{cpuHoles}】");}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern
{internal class MSIMainboard : IMainboard{private int cpuHoles = 1151;public MSIMainboard(){}public MSIMainboard(int cpuHoles){this.cpuHoles = cpuHoles;}public void InstallCPU(){Console.WriteLine($"微星主板,主板插槽数为【{cpuHoles}】");}}//Class_end
}
5、分别创建CPU与主板的工厂
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern
{/// <summary>/// 创建CPU的简单工厂/// </summary>internal class CPUFactory{/// <summary>/// 创建CPU对象方法/// </summary>/// <param name="type">CPU类型【1表示Intel;2表示AMD】</param>/// <returns></returns>public static ICPU CreateCPU(int type){ICPU cpu = null;switch (type){case 1:cpu = new IntelCPU();break;case 2:cpu = new AmdCPU();break;default:break;}return cpu;}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern
{/// <summary>/// 创建主板的简单工厂/// </summary>internal class MainboardFactory{/// <summary>/// 创建主板对象方法/// </summary>/// <param name="type">主板类型(1表示技嘉主板;2表示微星主板)</param>/// <returns></returns>public static IMainboard CreateMainboard(int type) {IMainboard mainboard = null;switch (type){case 1:mainboard = new GAMainboard();break;case 2:mainboard = new MSIMainboard();break;default:break;}return mainboard;} }//Class_end
}
6、编写装机工程师类实现组装电脑功能
/***
* Title:"设计模式" 项目
* 主题:装机工程师
* Description:
* 功能:客户告诉装机工程师自己选择的配件,让装机工程师组装;这样存在两个问题:
* 1、对于装机工程师,只知道CPU和主板的接口,但是不知道具体的实现
* 2、CPU与主板是需要相互匹配接口的,否则无法安装使用;但目前并没有维护这种关系,是客户随意选择的
*Date:2025
* Version:0.1版本
* Author:Coffee
* Modify Recoder:***/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern
{/// <summary>/// 装机工程师/// </summary>internal class InstallationEngineer{//定义装机需要的CPUprivate ICPU cpu = null;//定义装机需要的主板private IMainboard mainboard = null;/// <summary>/// 组装电脑/// </summary>/// <param name="cpuType">cpu类型</param>/// <param name="mainboardType">主板类型</param>public void InstallComputer(int cpuType,int mainboardType){//1、准备装机所需的配件PrepareHardwares(cpuType,mainboardType);//2、组装电脑//3、测试组装电脑的各个功能是否正常//4、交付客户}//准备装机的配件private void PrepareHardwares(int cpuType, int mainboardType){//直接找工厂获取对应的CPU与主板this.cpu = CPUFactory.CreateCPU(cpuType);this.mainboard=MainboardFactory.CreateMainboard(mainboardType);//测试配件是否可用this.mainboard.InstallCPU();this.cpu.Calculate();}}//Class_end
}
7、客户端通过装机工程师来组装电脑
using AbstractFactoryPattern.AbstractFactory;
using AbstractFactoryPattern.DAO;
using AbstractFactoryPattern.ExtandAbstractFactory;namespace AbstractFactoryPattern
{internal class Program{static void Main(string[] args){InstallationEngineerTest();Console.ReadLine();}/// <summary>/// 测试装机工程师组装的电脑/// </summary>private static void InstallationEngineerTest(){Console.WriteLine($"\n测试装机工程师组装电脑——未使用抽象工厂模式");//创建装机工程师对象InstallationEngineer installationEngineer=new InstallationEngineer();//客户告诉装机工程师自己选择的配件,让装机工程师组装installationEngineer.InstallComputer(1,1);}}//Class_end
}
运行结果如下:
目前存在的问题:
我们可以看到虽然通过简单工厂可以组装电脑了,但是对与装机工程师来说,它只知道CPU和主板的接口,而不知道具体的实现;他也无法知道CPU与主板的匹配关系【简单工厂并没有维护类似针脚匹配的关系内容】;这样就会存在CPU于主板的针脚数不同,从而导致电脑根本无法组装的问题出现; 我们可以使用抽象工厂模式来维护各个配件的关系。
2.2、使用抽象工厂方法模式的示例
由于装机工程师要组装电脑对象,需要相应的配件对象(如:CPU、主板等配件),我们就可以创建一个抽象工厂给装机工程师使用,在这个抽象工厂里面定义抽象地创建CPU与主板配件的方法(即:这个抽象的工厂就相当于一个抽象的装机方案,在这个方案里面各个配件都是可以相互匹配的);
1、创建抽象工厂接口用来约束需相互匹配关联的对象
/***
* Title:"设计模式" 项目
* 主题:典型抽象工厂
* Description:
* 功能:抽象工厂模式的本质是【选择产品簇(系列)的实现】
* 抽象工厂模式定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
*
* 抽象工厂的功能:抽象工厂的功能是为一系列相关对象或相互依赖对象创建一个接口【抽象工厂其实是一个产品系列】
* 【特别注意:这个接口内的方法不是任意堆砌的,而是一系列相关或相互依赖的方法】
* 抽象工厂通常实现为接口;
* 切换产品系列:由于抽象工厂定义的一系列对象通常是相关或相互依赖的,这些产品构成来了一个系列或产品簇;
* 这就带来了很大的灵活性,即切换一个产品簇的时候,只要提供不同的抽象工厂实现就可以
*
*
*Date:2025
* Version:0.1版本
* Author:Coffee
* Modify Recoder:***/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern.AbstractFactory
{/// <summary>/// 抽象工厂接口,声明创建抽象产品对象的操作/// </summary>internal interface IInstallationSchema{//创建CPU对象ICPU CreateCPU();//创建主板对象IMainboard CreateMainboard();}//Interface_end
}
2、创建具体类继承抽象工厂接口真正实现所需对象且维护好相互匹配关系
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern.AbstractFactory
{/// <summary>/// 装机方案一:Intel的CPU+技嘉的主板/// 这里创建CPU和主板的时候,统一为1151接口匹配对应上的,不会出问题/// </summary>internal class InstallationSchema1 : IInstallationSchema{public ICPU CreateCPU(){return new IntelCPU(1151);}public IMainboard CreateMainboard(){return new GAMainboard(1151);}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern.AbstractFactory
{/// <summary>/// 装机方案二:AMD的CPU+微星的主板/// 这里创建CPU和主板的时候,统一为940接口匹配对应上的,不会出问题/// </summary>internal class InstallationSchema2 : IInstallationSchema{public ICPU CreateCPU(){return new AmdCPU(940);}public IMainboard CreateMainboard(){return new MSIMainboard(940);}}//Class_end
}
3、再来实现装机工程师类来组装电脑
这里实现的装机工程师类与前面简单工厂的装机工程师类相比,主要的变化是:不再由客户端出入CPU与主板的参数;而是直接传入具体的装机方案(都是一套相互匹配产品簇(系列)),这样就避免了单独选择CPU与主板而出现的不匹配无法组装问题:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern.AbstractFactory
{internal class InstallationEngineer2{//定义获取组装电脑所需的CPUprivate ICPU cpu;//定义获取组装电脑所需的主板private IMainboard mainboard;/// <summary>/// 装机工程师组装电脑/// </summary>/// <param name="installationSchema">装机方案</param>public void InstallComputer(IInstallationSchema installationSchema){//1、准备好装机所需的配件PrepareHardwares(installationSchema);//2、组装电脑//3、测试电脑//4、交付客户}//准备装机所需的配件private void PrepareHardwares(IInstallationSchema installationSchema){//这里需要CPU与主板的具体对象,可工程师并不知道如何创建,该怎么办?//可以使用抽象工厂来获取相应的对象this.cpu=installationSchema.CreateCPU();this.mainboard=installationSchema.CreateMainboard();//测试配件是否正常this.mainboard.InstallCPU();this.cpu.Calculate();}}//Class_end
}
4、客户端创建装机工程师来组装电脑
using AbstractFactoryPattern.AbstractFactory;
using AbstractFactoryPattern.DAO;
using AbstractFactoryPattern.ExtandAbstractFactory;namespace AbstractFactoryPattern
{internal class Program{static void Main(string[] args){InstallationEngineer2Test();Console.ReadLine();}/// <summary>/// 测试装机工程师2组装的电脑/// </summary>private static void InstallationEngineer2Test(){Console.WriteLine($"\n测试装机工程师组装电脑——使用抽象工厂模式");//创建装机工程师对象InstallationEngineer2 installationEngineer2 = new InstallationEngineer2();Console.WriteLine($"\n测试装机工程师组装电脑——使用方案一");//获取客户选择的装机方案一IInstallationSchema installationSchema = new InstallationSchema1();//客户告诉装机工程师自己选择的配件,让装机工程师组装installationEngineer2.InstallComputer(installationSchema);Console.WriteLine($"\n测试装机工程师组装电脑——使用方案二");//获取客户选择的装机方案一IInstallationSchema installationSchema2 = new InstallationSchema2();//客户告诉装机工程师自己选择的配件,让装机工程师组装installationEngineer2.InstallComputer(installationSchema2);}}//Class_end
}
运行结果如下:
如上定义抽象工厂模式接口配合具体的方案是实现了配件间的相互匹配问题;但如果我们想要在当前的具体的产品簇(系列)里面新增一个配件(如:需要新增内存条)那么在现有的典型抽象工厂方法模式下就需要现在抽象工厂模式接口里面定义一个创建内存条的对象;然后还需要在所有继承了该抽象接口的具体类里面实现新增的内存条内容,这样就非常麻烦了,十分的不灵活。
2.3、使用可扩展抽象工厂方法模式的示例
针对典型抽象工厂方法对于新增产品麻烦不灵活的问题,我们可以在编写可扩展的抽象工厂接口来解决这个问题(即:我们的整个抽象工厂接口里面不需要定义很多的方法,只是定义一个创建产品的方法,然后给这个方法设置一个参数,通过这个参数来判断具体创建什么产品对象)
1、创建可扩展的抽象工厂接口
/***
* Title:"设计模式" 项目
* 主题:可拓展的抽象抽象工厂(不太安全)
* Description:
* 功能:抽象工厂模式的本质是【选择产品簇(系列)的实现】
* 抽象工厂本质:是选择单个产品的实现,虽然一个类里面可以有多个工厂方法,但是这些方法之间一般是没有联系的;
* 抽象工厂着重的就是为一个产品簇选择实现;抽象工厂方法通常是有联系的,它们都是产品某一部分或是相互依赖的
*
* 抽象工厂模式的优点:
* 1、分离接口和实现(客户端使用抽象工厂来创建需要的对象,而客户端根本不知道具体的实现是谁,客户端只是面向产品的接口编程而已)
* 2、使得切换产品系列变得容易(因为一个具体的工厂实现代表一个产品系列【如:Schema1代表装机方案一:Intel的CPU+技嘉的主板;
* Schema2代表装机方案二:AMD的CPU+微星的主板;客户选用不同的模式,就相当于切换不同的产品系列】)
*
* 抽象工厂模式的缺点:
* 1、不太容易扩展新的产品(典型的抽象工厂方法若需要给整个产品新添加一个产品,那就需要修改抽象工厂,
* 这样会导致修改所有的工厂实现类;可扩展的抽象工厂可以解决新增产品问题,但是又不够安全)
* 2、容易造成类层次复杂(在使用抽象工厂模式时,若需要选择的层次过多,那么会造成整个类层次变得复杂)
*
* 何时选用抽象工厂模式?
* 1、如果希望一个系统独立于它的产品创建、组合和表示的时候【即:希望一个系统只知道产品的接口,而不关心实现】
* 2、如果一个系统要由多个产品系列中的一个来配置的时候【即:可以动态的切换多个产品簇(系列)】
* 3、如果要强调一系列相关产品的接口,以便联合使用它们的时候
*
*Date:2025
* Version:0.1版本
* Author:Coffee
* Modify Recoder:***/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern.ExtandAbstractFactory
{/// <summary>/// 可拓展的抽象工厂接口/// </summary>internal interface IExtandAbstractFacoty{/// <summary>/// 一个通用的创建产品对象方法/// </summary>/// <param name="type">具体创建产品类型标识</param>/// <returns>返回被创建出的产品对象</returns>object CreateProduct(int type);}//Interface_end
}
2、编写一个类继承该可扩展的抽象工厂接口实现具体的各个配件匹配方案
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern.ExtandAbstractFactory
{/// <summary>/// 装机方案一:Intel的CPU+技嘉的主板/// 该方案里面创建的CPU与主板是可以匹配对应上的/// </summary>internal class Schema1 : IExtandAbstractFacoty{/// <summary>/// 创建产品/// </summary>/// <param name="type">这里的类型是表示对应的产品对象(如:1表示CPU;2表示主板)</param>/// <returns></returns>public object CreateProduct(int type){object obj = null;//type为表四创建的产品类型(如:1表示CPU,2表示主板)switch (type){case 1:obj = new IntelCPU(1151);break;case 2:obj = new GAMainboard(1151);break;default:break;}return obj;}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern.ExtandAbstractFactory
{/// <summary>/// 装机方案二:AMD的CPU+微星的主板/// 该方案里面创建的CPU与主板是可以匹配对应上的/// </summary>internal class Schema2 : IExtandAbstractFacoty{/// <summary>/// 创建产品/// </summary>/// <param name="type">这里的类型是表示对应的产品对象(如:1表示CPU;2表示主板)</param>/// <returns></returns>public object CreateProduct(int type){object obj = null;switch (type){case 1:obj = new AmdCPU(940);break;case 2:obj = new MSIMainboard(940);break;default:break;}return obj;}}//Class_end
}
3、编写装机工程师类实现组装电脑功能
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern.ExtandAbstractFactory
{internal class InstallationEngineer3{//定义组装电脑所需的CPU对象private ICPU cpu = null;//定义组装电脑所需的主板对象private IMainboard mainboard = null;public void InstallComputer(IExtandAbstractFacoty schema){//1、准备好装机所需的配件PrepareHardwares(schema);//2、组装电脑//3、测试电脑//4、交付客户}//准备装机所需的配件private void PrepareHardwares(IExtandAbstractFacoty schema){//这里使用方案获取需要的配件对象this.cpu = (ICPU)schema.CreateProduct(1);this.mainboard=(IMainboard)schema.CreateProduct(2);//测试配件是否正常this.mainboard.InstallCPU();this.cpu.Calculate();}}//Class_end
}
4、客户端使用该组装工程师类组装电脑
using AbstractFactoryPattern.AbstractFactory;
using AbstractFactoryPattern.DAO;
using AbstractFactoryPattern.ExtandAbstractFactory;namespace AbstractFactoryPattern
{internal class Program{static void Main(string[] args){InstallationEngineer3Test();Console.ReadLine();}/// <summary>/// 测试装机工程师3组装的电脑/// </summary>private static void InstallationEngineer3Test(){Console.WriteLine($"\n测试装机工程师组装电脑——使用拓展抽象工厂模式");//创建装机工程师对象InstallationEngineer3 installationEngineer3 = new InstallationEngineer3();Console.WriteLine($"\n使用客户选择的装机方案一【只有CPU与主板】");//获取客户选择的装机方案2IExtandAbstractFacoty installationSchema1 = new Schema1();//客户告诉装机工程师4自己选择的配件,让装机工程师组装(若此时没有对信息的memory判断就会报错)installationEngineer3.InstallComputer(installationSchema1);Console.WriteLine($"\n使用客户选择的装机方案二【只有CPU和主板");//获取客户选择的装机方案3IExtandAbstractFacoty installationSchema2 = new Schema2();//客户告诉装机工程师4自己选择的配件,让装机工程师组装installationEngineer3.InstallComputer(installationSchema2);}}//Class_end
}
运行结果如下:
如上是可扩展的抽象工厂的基本实现;从客户端的代码会发现,为什么说这种方式不安全呢?
【 是因为创建产品后返回的是object对象,但我们使用的时候需要转为具体的对象;如果此次返回的对象与我们需要转换的对象没有匹配上,但还是需要强制转为我们需要的对象,此时就会发生错误;就是这一点不太安全】。
5、我们接下来就使用扩展抽象方法模式来新增产品,体会以下可扩展抽象方法模式的灵活性
《1》新增内存接口用来约束内存的功能行为
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern
{/// <summary>/// 内存接口/// </summary>internal interface IMemory{//内存具有缓存数据的能力,仅示意void CacheDatas();}//Interface_end
}
《2》编写一个闪迪类继承内存接口实现具体的功能行为
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern
{/// <summary>/// 闪迪内存条/// </summary>internal class SanDiskMemory:IMemory{//定义内存条的频率(HZ)private int memoryRate = 2133;public SanDiskMemory(){}public SanDiskMemory(int memoryRate){this.memoryRate = memoryRate;}public void CacheDatas(){Console.WriteLine($"现在使用闪迪内存条,内存条频率是【{memoryRate}】");}}//Class_end
}
《3》创建一个方案继承可扩展抽象工厂接口实现具体的内容
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern.ExtandAbstractFactory
{internal class Schema3 : IExtandAbstractFacoty{/// <summary>/// 创建产品/// </summary>/// <param name="type">这里的类型是表示对应的产品对象(如:1表示CPU;2表示主板;3表示内存条)</param>/// <returns>返回具体的产品对象</returns>public object CreateProduct(int type){object obj = null;switch (type){case 1:obj = new AmdCPU(1151);break;case 2:obj = new MSIMainboard(1151);break;case 3:obj = new SanDiskMemory(3200);break;default:break;}return obj;}}//Class_end
}
《4》编写装机工程师类实现组装电脑
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace AbstractFactoryPattern.ExtandAbstractFactory
{/// <summary>/// 装机工程师4/// </summary>internal class InstallationEngineer4{//定义组装电脑所需的CPU对象private ICPU cpu = null;//定义组装电脑所需的主板对象private IMainboard mainboard = null;//定义内存头条对象private IMemory memory = null;public void InstallComputer(IExtandAbstractFacoty schema){//1、准备好装机所需的配件PrepareHardwares(schema);//2、组装电脑//3、测试电脑//4、交付客户}//准备装机所需的配件private void PrepareHardwares(IExtandAbstractFacoty schema){//这里使用方案获取需要的配件对象this.cpu = (ICPU)schema.CreateProduct(1);this.mainboard=(IMainboard)schema.CreateProduct(2);//新增内存条对象this.memory=(SanDiskMemory)schema.CreateProduct(3);//测试配件是否正常this.mainboard.InstallCPU();this.cpu.Calculate();//新增内存条判断,这是因为前面的模式没有内存条,若不判断直接使用就会报错if (memory!=null){memory.CacheDatas();}}}//Class_end
}
注意:这里之所以需要在测试内存条功能的时候增加一个if判断,原因是为了要同时满足以前和现在的要求(以前的客户端,它调用的时候没有内存条对象,若直接调用这个最新的模式的到内存功能时就会报错;因此需要添加一个判断)。
《5》客户端调用工程师类实现组装电脑
using AbstractFactoryPattern.AbstractFactory;
using AbstractFactoryPattern.DAO;
using AbstractFactoryPattern.ExtandAbstractFactory;namespace AbstractFactoryPattern
{internal class Program{static void Main(string[] args){InstallationEngineer4Test();Console.ReadLine();}/// <summary>/// 测试装机工程师4组装的电脑/// </summary>private static void InstallationEngineer4Test(){Console.WriteLine($"\n测试装机工程师组装电脑——使用拓展抽象工厂模式");//创建装机工程师对象InstallationEngineer4 installationEngineer4 = new InstallationEngineer4();Console.WriteLine($"\n使用客户选择的装机方案二【只有CPU与主板】");//获取客户选择的装机方案2IExtandAbstractFacoty installationSchema2 = new Schema2();//客户告诉装机工程师4自己选择的配件,让装机工程师组装(若此时没有对信息的memory判断就会报错)installationEngineer4.InstallComputer(installationSchema2);Console.WriteLine($"\n使用客户选择的装机方案三【有CPU、主板和内存条】");//获取客户选择的装机方案3IExtandAbstractFacoty installationSchema3 = new Schema3();//客户告诉装机工程师4自己选择的配件,让装机工程师组装installationEngineer4.InstallComputer(installationSchema3);}}//Class_end
}
运行结果如下:
三、项目源码工程
kafeiweimei/Learning_DesignPattern: 这是一个关于C#语言编写的基础设计模式项目工程,方便学习理解常见的26种设计模式https://github.com/kafeiweimei/Learning_DesignPattern