本文转载自微信公众号《程序喵大师》,作者程序喵大师。转载本文请联系程序大师喵公众号。01简单工厂方法简单工厂方法可能是最常见的工厂类创建模式。角色有几个,一个是抽象的产品角色,一个是具体的产品角色,多个具体的产品就可以了。抽象成同一个抽象产物。以操作系统为例。操作系统作为一个抽象的产品,有几个具体的产品角色,包括Windows操作系统、Android操作系统和iOS操作系统。有一个操作系统工厂,可以根据不同的需要生产不同内核的操作系统。这个操作系统工厂就是最后一个角色:工厂角色。#includeenumclassBallEnum{BasketBall=1,SocketBall=2};classBall{public:Ball(){}virtual~Ball(){}virtualvoidPlay(){}};classBasketBall:publicBall{public:voidPlay()override{std::cout<<"playsocketball\n";}};classSocketBall:publicBall{public:voidPlay()override{std::cout<<"playsocketball\n";}};classSimpleFactory{public:staticBall*CreateBall(BallEnumtype);};Ball*SimpleFactory::CreateBall(BallEnumtype){switch(type){caseBallEnum::BasketBall:returnnewBasketBall();caseBallEnum::SocketBall:returnnewSocketBall();}returnnullptr;}intmain(){Ball*basket=SimpleFactory::CreateBall(BallEnum::BasketBall);basket->Play();Ball*socket=SimpleFactory::CreateBall(BallEnum::SocketBall);socket->Play();return0;}在简单工厂方法中,有a专用工厂类根据不同的参数返回不同具体产品类的实例。这些具体的产品可以抽象出同一个抽象产品,即它们有一个共同的父类。通过上面的代码,你可能也看到了简单工厂方法的优点,它实现了对象创建和使用逻辑的分离,只需要传入不同的参数就可以得到具体具体类的实例。但是简单工厂方法也有一些缺点。当添加新产品时,需要修改工厂类的创建逻辑。如果产品类型较多,工厂类逻辑可能过于复杂,不利于系统维护。它适用于特定的产品类型。以后比较少,基本不会增加新类型的场景,所以工厂类的业务逻辑不会太复杂。02工厂方法模式为了解决上面简单工厂方法模式的不足,对工厂方法模式进行了进一步的抽象。工厂类不再负责所有产品的构建。每个具体的产品都有对应的工厂,所以在添加新产品的时候。现有工厂类的创建逻辑不会改变。这些工厂也抽象出一个抽象工厂。可以理解为四种角色,抽象产品,具体产品,抽象工厂,具体工厂。其实就是把简单工厂模型中的工厂类进一步抽象出来。让我们看一下代码:#includeenumclassBallEnum{BasketBall=1,SocketBall=2};classBall{public:Ball(){}virtual~Ball(){}virtualvoidPlay(){}};classBasketBall:publicBall{public:voidPlay()覆盖{std::cout<<"打篮球\n";}};classSocketBall:publicBall{public:voidPlay()override{std::cout<<"playsocketball\n";}};classFactoryBall{public:virtual~FactoryBall(){}virtualBall*CreateBall()=0;};classBasketBallFactory:publicFactoryBase{public:Ball*CreateBall()override{returnnewBasketBall();}};classSocketBallFactory:publicFactoryBase{public:Ball*CreateBall()override{returnnewSocketBall();}};intmain(){FactoryBase*factory;BallEnumball_type=BallEnum::SocketBall;switch(ball_type){caseBallEnum::BasketBall:factory=newBasketBallFactory();break;caseBallEnum::SocketBall:factory=newSocketBallFactory();break;}Ball*ball=factory->CreateBall();球->Play();return0;}工厂模式提高了系统的可扩展性,完全符合封闭性原则,当新增特定产品时,不会对现有系统进行任何修改。当你不知道未来会有多少具体的产品时,可以考虑使用工厂模式,因为它不会降低现有系统的稳定性。但它也有缺点。每当添加一个新产品时,不仅需要添加一个新的对应产品类别,还需要添加一个与该产品对应的新工厂。系统的复杂度比较高。如何解决,可以再抽象一下:03抽象工厂模式在工厂方法中,每一个抽象的产品都会有一个抽象工厂,这样在添加新产品的时候,会添加两个类,一个是具体的产品类,另一个是特定的产品类别。对于工厂类,我们可以认为多个抽象产品对应一个抽象工厂,可以有效减少具体工厂类的数量,见如下代码:#includeenumclassBallEnum{BasketBall=1,SocketBall=2};classBall{public:Ball(){}virtual~Ball(){}virtualvoidPlay(){}};classBasketBall:publicBall{public:voidPlay()override{std::cout<<"playbasketball\n";}};classSocketBall:publicBall{public:voidPlay()override{std::cout<<"playsocketball\n";}};classPlayer{public:Player(){}virtual~Player(){}virtualvoidName(){}};classBasketBallPlayer:publicPlayer{public:voidName()override{std::cout<<"BasketBallplayer\n";}};classSocketBallPlayer:publicPlayer{public:voidName()override{std::cout<<"SocketBallplayer\n";}};classFactoryBase{public:virtual~FactoryBall(){}virtualBall*CreateBall()=0;virtualPlayer*CreatePlayer()=0;};classBasketBallFactory:publicFactoryBase{public:Ball*CreateBall()override{returnnewBasketBall();}Player*CreatePlayer()override{returnnewBasketBallPlayer();}};classSocketBallFactory:publicFactoryBase{public:Ball*CreateBall()override{returnnewSocketBall();}Player*CreatePlayer()override{returnnewSocketBallPlayer();}};intmain(){FactoryBase*factory;BallEnumball_type=BallEnum::SocketBall;switch(ball_type){caseBallEnum::BasketBall:factory=newBasketBallFactory();break;caseBallEnum::SocketBall:factory=newSocketBallFactory();break;}Ball*ball=factory->CreateBall();Player*player=factory->CreatePlayer();ball->Play();player->Name();return0;}总结系统的复杂度不会消除,只能转稳定部分和不稳定部分只是我们要合理选择边界,仔细思考,考虑哪部分是稳定的部分,哪部分是不稳定的部分。简单工厂方法模式中的if-else逻辑在工厂类中。如果在此处添加新商品时出现bug,可能会导致所有商品创建失败。这就是不稳定的部分,所以有了工厂方法模式,在工厂类内部创建一个稳定的部分,把不稳定的逻辑转移到外面。