创建型模式--Abstract Factory模式(二)
假设直升飞机和战斗机都由机头, 机身, 机尾组成. 直升飞机由直升飞机厂生产, 战斗机有战斗机厂生产.
两种飞机的生产过程都是生产机头, 机身, 机尾, 然后组装(也就是说两种飞机的生成流程是一样的).
(机头, 机身, 机尾的生产顺序没有严格规定, 当然有严格规定也行).
(两种飞机的组成一样才使得生产流程一样.)
这个场景就符合Abstract Factory 模式.
抽象飞机工厂1个(CPlaneFactory)
具体飞机工厂2个(CHelicopterFactory和CBattlePlaneFactory)
抽象部件3个(CHead, CBody, CTail)
具体部件6个(CHelicopterHead, CHelicopterBody, CHelicopterTail和CBattlePlaneHead, CBattlePlaneBody, CBattlePlaneTail)
如图:
工厂的MakeHead, MakeBody, MakeTail函数就是new对应飞机的部件.
// 伪代码
if(生产直升飞机)
飞机工厂 = 直升飞机工厂;
else if(生产战斗机)
飞机工厂 = 战斗机工厂;
// 两种飞机的生产流程是一致的
飞机工厂.生产机头;
飞机工厂.生产机身;
飞机工厂.生产机机尾;
飞机工厂.组装;
// 用户调用 CPlaneFactory* pCPlaneFactory = 0; // 在这里是用户 // 根据用户自己的需求生成具体的工厂对象 if(bMakeHolicopter) { pCPlaneFactory = new CHelicopterFactory; } else { pCPlaneFactory = new CBattlePlaneFactory; } // 生产机头, 机身, 机尾 CHead* pCHead = pCPlaneFactory->MakeHead(); CBody* pCBody = pCPlaneFactory->MakeBody(); CTail* pCTail = pCPlaneFactory->MakeTail(); // 用户的其他调用, 例如组装 ...
1. 用户在调用的过程中, 除了在创建工厂的时候需要具体工厂类之外, 其他地方都是使用抽象类定义的接口. 这样使得用户与具体的类解耦, 假设现在用户从生产直升飞机改为生成战斗机, 只需要修改bMakeHolicopter = false其他地方的代码都不需要修改.
2. 具体类的内部实现改变了, 只要接口没有变, 用户都不需要修改其调用代码.
3. 假设现在需要增加航天飞机的生生产, 航天飞机的组成和生产流程是和直升飞机一样. 我们只需增加CShuttleFactory, CShuttleHead, CShuttleBody, CShuttleTail 四个具体类, 然后增加一处创建CShuttleFactory的代码即可。增加代码通常比修改代码带来的工作量要少. 因为其他两种飞机的具体类并没有被修改, 可以不需要重新测试或者只需要简单测试即可.
4. 假设飞机不是有机头, 机身, 机尾3个部件组成, 而是由10部件组成, 那么3种飞机需要的具体了是 3 + 3 * 10 = 33个具体类组成. 33个具体类我不知道算不算多, 但是这里要说明的一点我们在设计时要考虑类的粒度.
5. 假设现在设计有变, 两种飞机要增加一种部件(例如引擎). 那么, 在这种情况变化就大了, 需要做的事情是: a. 增加1个引擎抽象类, 2个引擎具体类; b. 抽象工厂类增加一个MakeEngine接口, 抽象类接口的改变, 引起所有具体工厂类也要增加该接口的实现.
这种的修改工作量就特别大和容易出错. 因为这里不同第4点, 第4点只增加了代码, 而这里要大幅度的修改代码. 这种的修改通常是用户的需求有变化引起, 在Abstract Factory模式中遇到这种需求变化, 需要改动很大.
6. 假设现在直升飞机需要增加一种部件, 例如螺旋桨) 但是战斗机是没有螺旋桨的, 那怎么办? 这种情况, 就不适合使用Abstract Factory 模式了, 因为两种的飞机组成不同了, 生成流程不同了, 两个工厂生产的东西都不一致. 当然对于用户而言可以把相同部件部分使用Abstract Factory 模式, 不同部件部分, 用户自己判断. 看需求吧, 适合就好.
7. 部件类(这里的机头, 机身, 机尾等类)根据具体的需求也有自己定义的接口, 根据需求而定, 我自己假设的场景中没有接口.