8. 对象创建模式 之 工厂方法


        通过“对象创建”模式,绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。他是接口抽象之后的第一步工作

  • 典型模式
    •  Factory Method
    • Abstract Factory
    • Prototype
    • Builder

动机:

  • 在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化,
  • 如何应对这种变化?如何绕过常规的new,提供一种“封装机制”来避免客户程序和这种“具体对象创建工作”的紧耦合?

代码示例:

 文件分割器中的部分代码

class MainForm:public Form
{
public:
    void Button1_Click()
    {
        FileSpliter *spliter = new FileSpliter();
        spliter->split();
    } 
}

上面的New就是和具体类耦合了,没有支持未来的变化,导致后期的扩展很困难。

比如,上面时二进制文件的分割,我们想要支持txt文件的分割,图像文件的分割...

拿大概的代码:

class ISpliter
{
    virtual void split() = 0;
}
class BinSpliter : public ISpliter
{

}

class TxtSpliter : public ISpliter
{

}

class PictureSliter : public ISpliter
{

}


class MainForm:public Form
{
public:
    void Button1_Click()
    {
        ISpliter *spliter = new BinSpliter(); // 依赖具体类
        spliter->split();
    } 
}

上述代码中的new之前的ISpliter从具体依赖改变程了抽象依赖,是我们想要的,但是后面的new的具体类,仍然是细节依赖,所以仍然不行,不符合编译时依赖,即上述代码编译时,需要BinSpliter存在才能编译,违背依赖导致原则。

那上面的new是避免不了的,那有什么方法可以替代?

可以使用一种方法来返回一个对象。

VER1:

class SpliterFactory
{
public:
    ISpliter* CreateSpliter()
    {
        return new BinSpliter();
    }
};

class MainForm:public Form
{
public:
    void Button1_Click()
    {
        SpliterFactory factory;
        ISpliter *spliter = factory.CreateSpliter();
        spliter->split();
    } 
}

那如果按照上面的做法,解决了问题吗?其实没有。

因为SpliterFactory依赖BinSpliter,MainForm依赖SpliterFactory,那MainForm还是会依赖BinSpliter...(编译时依赖)

有什么方法可以将编译时依赖转为运行时依赖:virtual方法!!!

VER2:

class SpliterFactory
{
public:
    virtual ISpliter* CreateSpliter() = 0;
};

class MainForm:public Form
{
public:
    void Button1_Click()
    {
        SpliterFactory *factory;
        ISpliter *spliter = factory->CreateSpliter();
        spliter->split();
    } 
}

按照上面代码,其实基本理顺了,上面返回的spliter是个多态的创建,现在返回的是ISpliter,真正的创建,交给SpliterFactory的未来。

// 具体类
class BinSpliter : public ISpliter
{

}

class TxtSpliter : public ISpliter
{

}

class PictureSliter : public ISpliter
{

}

// 具体工厂
class BinSpliterFactory : public SpliterFactory
{
    virtual ISpliter* CreateSpliter()
    {
        return new BinSpliter();
    }
}

class TxtSpliterFactory : public SpliterFactory
{
    virtual ISpliter* CreateSpliter()
    {
        return new TxtSpliter();
    }
}

class PictureSliterFactory : public SpliterFactory
{
    virtual ISpliter* CreateSpliter()
    {
        return new PictureSliter();
    }
}

通过上面代码可以看到,每个具体的类,都对应一个具体的工厂,那工厂类怎么初始化呢?

class SpliterFactory
{
public:
    virtual ISpliter* CreateSpliter() = 0;
};

class MainForm:public Form
{
public:
    void Button1_Click()
    {
        SpliterFactory *factory; // ????
        ISpliter *spliter = factory->CreateSpliter();
        spliter->split();
    } 
}

肯定不能就地New的,一般做法:

class MainForm:public Form
{
    SpliterFactory *factory;
public:
    MainForm(SpliterFactory *factory)
    : this->factory = factory;
    {

    }
    void Button1_Click()
    {
        
        ISpliter *spliter = factory->CreateSpliter(); // 多台New
        spliter->split();
    } 
}

一定会有人问,虽然这个位置没有具体去创建具体的factory,那在别的位置,不还是要创建,那不是还是会产生依赖?

答案:会产生依赖

但是,我们当前考虑的是对MainForm的影响,会不会产生依赖,通过上面的修改,Mainform是没有具体类的依赖的。

我们并不是要把变化(对具体类的依赖)给消灭掉,而是将它赶到某个局部的地方,比如将一只猫关到笼子里,而不是让它在真个房间跳来跳去。

模式定义

        定义一个用于创建对象的接口(工厂类创建的虚接口),让子类(具体工厂类)决定实例化哪一个类。FactoryMethod使得一个类的示例化延迟(目的:解耦,手段:虚函数)到子类

                                                                                        --《设计模式》GOF

结构

MainForm依赖的是稳定的部分,而不是变化的部分。

 要点总结

  • Factory Method模式用于隔离类对象的使用者和具体类型之前的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱
  • Factory Method模式通过面向对象的手段,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好的解决了这种紧耦合的关系。
  • Factory Method模式解决“单个对象”的需求变化,缺点在于要求创建方法/参数相同
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值