您现在的位置是:首页 >技术交流 >设计模式之工厂模式网站首页技术交流

设计模式之工厂模式

bxp1321 2024-06-17 10:19:54
简介设计模式之工厂模式

工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。

简单工厂

public class Factory{
    public static ISample creator(int which){
        if (which==1)
            return new SampleA();
        else if (which==2)
            return new SampleB();
    }
}

那么在你的程序中,如果要创建ISample的实列时候可以使用

ISample sampleA=Factory.creator(1);

这样,在整个就不涉及到ISample的具体的实现类,达到封装效果,也就减少错误修改的机会

使用工厂方法 要注意几个角色,首先你要定义产品接口,如上面的Sample类的接口,产品接口下有ISample接口的实现类,如SampleA,其次要有一个Factory类,用来生成产品ISample接口的具体实例。

简单工厂增加新的工厂方法时需要修改工厂类,违反了开闭原则。

抽象工厂

工厂模式中有: 工厂方法(Factory Method) 抽象工厂(Abstract Factory).

这两个模式区别在于需要创建对象的复杂程度上。如果我们创建对象的方法变得复杂了,如上面工厂方法中是创建一个对象Sample,如果我们还有新的产品接口Sample2.

这里假设:Sample有两个实体类SampleA和SampleB,而Sample2也有两个实体类Sample2A和Sample2B

那么,我们就将上例中Factory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现,下面就是将上例中的Factory拓展成抽象工厂:

public abstract class Factory{
    public abstract Sample creator();
    public abstract Sample2 creator(String name);
}
public class SimpleFactory extends Factory{
    public Sample creator(){
        .........
        return new SampleA
    }
    public Sample2 creator(String name){
        .........
        return new Sample2A
    }
}
 
public class BombFactory extends Factory{
    public Sample creator(){
        ......
        return new SampleB
    }
    public Sample2 creator(String name){
        ......
        return new Sample2B
    }
}

从上面看到两个工厂各自生产出一套Sample和Sample2,也许你会疑问,为什么我不可以使用两个工厂方法来分别生产Sample和Sample2?

抽象工厂还有另外一个关键要点,是因为 SimpleFactory内,生产Sample和生产Sample2的方法之间有一定联系,所以才要将这两个方法捆绑在一个类中,这个工厂类有其本身特征,也许制造过程是统一的,比如:制造工艺比较简单,所以名称叫SimpleFactory。

在实际应用中,工厂方法用得比较多一些,而且是和动态类装入器组合在一起应用,

工厂方法模式(Factory Method):定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法将一个类的实例化延迟到其子类。

对每一个子类产品都分别对应一个工厂子类,用来创建相应的产品,若增加了新的产品,只需相应增加工厂子类即可。

    工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得工厂方法可以被子类继承。

    工厂方法模式特点:

    (1)工厂方法模式是对简单工厂模式的稍微的改进。工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际工作推迟到子类中。

    (2)与简单工厂模式相比,制造产品的工厂类不再只有一个,而是每种具体产品类都对应一个生产它的具体工厂类。而具体工厂类的共同特征被提取出来形成一个抽象产品类,具体产品类都继承自抽象产品类。

    (3)当需要增加一种产品的时候,需要做的是:增加一种继承自抽象产品的具体产品类,增加一种继承在抽象工厂的具体工厂类,更改客户端的逻辑判断。

    UML类图如下:wKioL1nKYyyz8m_UAACkqNc0IQY250.jpg

 

2、工厂方法模式角色
    工厂接口:抽象工厂是工厂方法模式的核心,与调用者直接交互用来提供产品。工厂接口可以由抽象类来代替。

    工厂实现:工厂实现决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现。

    产品接口:产品接口的主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范。产品接口是调用者最为关心的,产品接口定义的优劣直接决定了调用者代码的稳定性。产品接口也可以用抽象类来代替,但要注意最好不要违反里氏替换原则。

    产品实现:实现产品接口的具体类,决定了产品在客户端中的具体行为。

3、工厂方法模式优缺点
优点:

    A、良好的封装性

    B、良好的扩展性

    C、屏蔽了产品类,用户不需要知道产品类的实例化过程。

    D、实现解耦,符合迪米特法则

    E、不用修改已有代码,开放封闭原则:对扩展开放,对更改封闭

缺点:

每增加一种产品,就需要增加一个对象的工厂。

4、工厂方法模式适用场景
    A、作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。

    B、工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。

    C、工厂模式是依靠抽象架构的,把实例化产品的任务交由实现类完成,扩展性比较好。当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。

    D、当客户程序不需要知道要使用对象的创建过程。 
        E、客户程序使用的对象存在变动的可能,或者根本就不知道使用哪一个具体的对象。
       在工厂方法模式中,要么将判断逻辑留在抽象工厂角色中,要么在客户程序中将具体工厂角色进行逻辑判断,而且产品对象创建条件的改变必然会引起工厂角色的修改。

二、工厂方法模式实现

IFactory抽象工厂类:
#ifndef IFACTORY_H
#define IFACTORY_H
#include "IProduct.h"
 
class IFactory
{
public:
    virtual IProduct* createProduct() = 0;
};
 
#endif // IFACTORY_H
ConcreteFactoryA具体工厂A:
#include "IFactory.h"
#include "ConcreteProductA.h"
 
class ConcreteFactoryA : public IFactory
{
public:
    ConcreteFactoryA(){}
    IProduct* createProduct()
    {
        IProduct* product = new ConcreteProductA();
        return product;
    }
};
 
#endif // CONCRETEFACTORYA_H
ConcreteFactoryB具体工厂B:
#ifndef CONCRETEFACTORYB_H
#define CONCRETEFACTORYB_H
#include "IFactory.h"
#include "ConcreteProductB.h"
 
class ConcreteFactoryB : public IFactory
{
public:
    ConcreteFactoryB(){}
    IProduct* createProduct()
    {
        IProduct* product = new ConcreteProductB();
        return product;
    }
};
 
#endif // CONCRETEFACTORYB_H
IProduct抽象产品类:
#ifndef IPRODUCT_H
#define IPRODUCT_H
 
class IProduct
{
public:
    virtual void show() = 0;
};
 
#endif // IPRODUCT_H
ConcreteProductA具体产品A:
#ifndef CONCRETEPRODUCTA_H
#define CONCRETEPRODUCTA_H
#include "IProduct.h"
 
#include <iostream>
using std::cout;
using std::endl;
 
class ConcreteProductA : public IProduct
{
public:
    ConcreteProductA(){}
    void show()
    {
        cout << "This is a ConcreteProductA" << endl;
    }
};
 
#endif // CONCRETEPRODUCTA_H
ConcreteProductB具体产品类B:
#ifndef CONCRETEPRODUCTB_H
#define CONCRETEPRODUCTB_H
#include "IProduct.h"
#include <iostream>
using std::cout;
using std::endl;
 
class ConcreteProductB : public IProduct
{
public:
    ConcreteProductB(){}
    void show()
    {
        cout << "This is a ConcreteProductB" << endl;
    }
};
 
#endif // CONCRETEPRODUCTB_H
客户端调用程序:
#include <iostream>
#include "IFactory.h"
#include "ConcreteFactoryA.h"
#include "ConcreteFactoryB.h"
 
using namespace std;
 
int main()
{
    IFactory* factoryA = new ConcreteFactoryA();
    IProduct* productA = factoryA->createProduct();
    productA->show();
 
    IFactory* factoryB = new ConcreteFactoryB();
    IProduct* productB = factoryB->createProduct();
    productB->show();
 
    return 0;
}

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。