设计模式——工厂模式

工厂模式在Java中使用非常广泛,其主要是为了解决接口选择的问题,顾名思义,工厂就是生产产品的。使用者只需要告诉工厂我需要什么产品,工厂就给你什么产品,使用者不需要关注产品是怎么生产出来的。以手机这个产品举例,先看代码

简单工厂模式

//工厂要生产手机,先定义一个接口
public interface Phone {
    //生产手机的方法。
    void make();
}
//如果我们要生产小米手机,创建一个小米手机类
public class MiPhone implements Phone {
    public MiPhone() {
        this.make();
    }
    //实现小米手机的生产方法。
    @Override
    public void make() {
        System.out.println("make xiaomi phone!");
    }
}
//我们还要生产苹果手机
public class IPhone implements Phone {
    public IPhone() {
        this.make();
    }
    //实现苹果手机的生产方法。
    @Override
    public void make() {
        System.out.println("make xiaomi phone!");
    }
}
//现在创建一个工厂类,用来生产小米手机和苹果手机。
public class PhoneFactory {
    public Phone makePhone(String phoneType) {
        //如果用户要小米手机,就实例化MiPhone
        if(phoneType.equalsIgnoreCas("MiPhone"){
            return new MiPhone();
        }
        //如果用要要苹果手机就实例化iPhone
         if(phoneType.equalsIgnoreCa("iPhone") {
            return new IPhone();
        }
        return null;
    }
}
//调用示例
public class Demo{
    public static void main(){
        //实例化工厂
        PhoneFacory facory=new PhoneFacory();
        //生产小米手机
        phone miphone = facory.makePhone("MiPhone");
        //生产苹果手机
        phone iphone = facory.makePhone("iPhone");
    } 
}

在C++中,可以使用抽象基类来实现接口

//定义一个抽象基类
class phone {
public:
   virtual void make() = 0;
};
//实现生产小米手机
class MiPhone :public phone {
public:
    MiPhone() {
        make();
    }
    void make() override {
        std::cout << "我是小米手机" << std::endl;
    }
};
//实现生产苹果手机
class IPhone :public phone {
public:
    IPhone() {
        make();
    }
    void make() override{
        std::cout << "我是苹果手机" << std::endl;
    }
};
//定义手机工厂类
class PhoneFacory {
public:
    phone * MakePhone(std::string phoneType) {
        if (phoneType._Equal("MiPhone"))
            return new MiPhone();
        if (phoneType._Equal("IPhone"))
            return new IPhone();
        return nullptr;
    }
};
//调用示例
int main()
{
    PhoneFacory facory;
    phone* miphone = facory.MakePhone("MiPhone");
    phone* iphone = facory.MakePhone("IPhone");
    //使用智能指针
    std::shared_ptr<phone> miphone2(facory.MakePhone("MiPhone"))
}

抽象工厂模式

所谓的抽象工厂模式,可以将工厂理解为一个超级工厂,围绕这个工厂创建其它工厂。前面实现的工厂模式,只能生成手机这一个品类的商品,当我们还想要电脑产品,比如小米笔记本和苹果笔记本,就可以使用抽象工厂模式,看代码。

//因为我们想要生产笔记本电脑。所以按照手机的方法定义一个电脑的产品接口。
public interface Laptop {
    //生产笔记本电脑的方法。
    public void make();
}
//小米笔记本电脑的生产
public class MiLaptop implements Laptop{
    public void make() override {
        std::cout << "我是小米笔记本电脑" << std::endl;
    }
}
//苹果笔记本电脑
public class MacLaptop implements Laptop{
    public void make() override{
        std::cout << "我是苹果笔记本电脑" << std::endl;
    }
}
//定义一个抽像工厂来生成手机和电脑两个品类的商品
public abstract class AbstractFactory{
    //这个工厂生产手机的方法
    public abstract phone makePhone(string phoneType);
    //生产笔记本电脑的方法
    public abstract Laptop makeLaptop(string laptopType);
}
//扩展一下之前的手机工厂
public class PhoneFactory extends AbstractFactory {
    @Override
    public Phone makePhone(String phoneType) {
        //如果用户要小米手机,就实例化MiPhone
        if(phoneType.equalsIgnoreCas("MiPhone"){
            return new MiPhone();
        }
        //如果用要要苹果手机就实例化iPhone
         if(phoneType.equalsIgnoreCa("iPhone") {
            return new IPhone();
        }
        return null;
    }
    @Override
    public Laptop makeLaptop(string laptopType){
        return null;
    }
}
//实现一个笔记本的工厂
public class LaptopFactory extends AbstractFactory {
    @Override
    public Phone makePhone(String phoneType) {
        
        return null;
    }
    @Override
    public Laptop makeLaptop(string laptopType){
        //如果用户要小米笔记本,就实例化MiLaptop
        if(phoneType.equalsIgnoreCase("MiLaptop"){
            return new MiLaptop();
        }
        //如果用要要苹果笔记本就实例化MacLaptop
         if(phoneType.equalsIgnoreCase("MacLaptop") {
            return new MacLaptop();
        }
        return null;
    }
}
//创建一个工厂生成器,来选择工厂
public class FactoryProducer{
    public static AbstractFactory getFactory(string factoryType){
        if (factoryType.equalsIgnoreCase("phone"))
             return new PhoneFactory();
        if (factoryType.equalsIgnoreCase("laptop"))
            return new LaptopFactory();
        return null;
    }
}

//使用示例
public class Demo{
    public static void main(string[] args){
        //获取手机工厂
        AbstractFactory phoneFactory = FactoryProducer.getFactory("phone");
        //生产小米手机
        phone miphone = phoneFactory.makePhone("MiPhone");
        //生产苹果手机
        phone iphone = phonefactory.makePhone("iphone");
        //获取笔记本工厂
        AbstractFactory laptopFactory = FactoryProducer.getFactory("laptop");
        //获取小米笔记本
        Laptop miLaptop = laptopFactory.makeLaptop("MiLaptop");
        //获取苹果笔记本
        Laptop macLaptop = laptopFactory.makeLaptop("MacLaptop");
    }
}

c++中的实现类似

//定义一个笔记本接口
class Laptop{
public:
    virtual void make() = 0;
}
//定义小米笔记本的实现
class MiLaptop :public Laptop
{
public:
    MiLaptop(){
        make();
    }
    void make() override {
        std::cout << "我是小米笔记本" << std::endl;
    }
}
//苹果笔记本的实现
class MacLaptop :public Laptop
{
public:
    MacLaptop(){
        make();
    }
    void make() override {
        std::cout << "我是苹果笔记本" << std::endl;
    }
}
//定义抽象工厂
class AbstractFactory
{
public:
   virtual phone * makePhone(std::string phoneType) =0;
   virtualLaptop * makeLaptop(std::string laptopType)=0;
}
//扩展前面的手机工厂
class phoneFactory:public AbstractFactory
{
public:
    phone * makePhone(std::strig phoneType) override{
        if (phoneType._Equal("MiPhone"))
            return new MiPhone();
        if (phoneType._Equal("IPhone"))
            return new IPhone();
        return nullptr;
    }
private:
    Laptop * makeLaptop(std::string laptopType){
        return nullptr;
    }
}
//实现笔记本电脑工厂
class LaptorFactory:public AbstractFactory
{
private:
    phone * makePhone(std::strig phoneType) override{
        
        return nullptr;
    }
public:
    Laptop * makeLaptop(std::string laptopType){
        if (phoneType._Equal("MiLaptop"))
            return new MiLaptop();
        if (phoneType._Equal("MacLaptop"))
            return new MacLaptop();
        return nullptr;
    }  
}
//创建一个工厂生成器,来选择工厂
class FactoryProducer{
public: 
static AbstractFactory* getFactory(string factoryType){
        if (factoryType._Equal("phone"))
             return new PhoneFactory();
        if (factoryType._Equal("laptop"))
            return new LaptopFactory();
        return null;
    }
}
//调用示例
int main(){
    //获取手机工厂
    AbstractFactory * phoneFactory = FactoryProducer::getFactory("phone");
    //获取小米手机
    phone * miphone = phoneFactory->makePhone("MiPhone");
    phone * iphone = phoneFactory->makePhone("IPhone");
    //获取笔记本工厂
    AbstractFactory * laptopFactory = FactoryProducer::getFactory("Laptop");
    //获取小米笔记本
    Laptop * miLaptop = laptopFactory->makeLaptop("MiLaptop");
    //获取苹果笔记本
    Laptop * MacLaptop = laptopFactory->makeLaptop("MacLaptop");
}

例子很简单,只实现了一个接口,展示了工厂模式的实现和原理,可能体现不出工厂模式的作用,工厂模式究竟有什么用,在什么情况下用,这里的一篇博文我觉得写的非常好。https://www.cnblogs.com/wangenxian/p/10787785.html
以下为这篇博客的全文。
工厂模式的实现方式和原理都不难理解和掌握。但是,在学习完之后,发现网上给的例子,根本体现不了工厂模式的作用。先不说存在有的例子本身就是错误的,主要是例子中的代码太简单,可以说没必要用工厂模式,只不过是为了说明实现方式和原理。所以,会产生一种错觉:还不如直接new 一个对象来的方便,有效。

的确,设计模式本身就有其适用的场景,并不是滥用的,否则还不如不用。

现在,我记录一下在翻阅一些资料后,自己的理解。

首先,工厂模式是为了解耦:把对象的创建和使用的过程分开。就是Class A 想调用 Class B ,那么A只是调用B的方法,而至于B的实例化,就交给工厂类。

其次,工厂模式可以降低代码重复。如果创建对象B的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。我们可以这些创建对象B的代码放到工厂里统一管理。既减少了重复代码,也方便以后对B的创建过程的修改维护。(当然,我个人觉得也可以把这些创建过程的代码放到类的构造函数里,同样可以降低重复率,而且构造函数本身的作用也是初始化对象。不过,这样也会导致构造函数过于复杂,做的事太多,不符合java 的设计原则。)

由于创建过程都由工厂统一管理,所以发生业务逻辑变化,不需要找到所有需要创建B的地方去逐个修正,只需要在工厂里修改即可,降低维护成本。同理,想把所有调用B的地方改成B的子类B1,只需要在对应生产B的工厂中或者工厂的方法中修改其生产的对象为B1即可,而不需要找到所有的new B()改为new B1()。

另外,因为工厂管理了对象的创建逻辑,使用者并不需要知道具体的创建过程,只管使用即可,减少了使用者因为创建逻辑导致的错误。

举个例子:

一个数据库工厂:可以返回一个数据库实例,可以是mysql,oracle等。

这个工厂就可以把数据库连接需要的用户名,地址,密码等封装好,直接返回对应的数据库对象就好。不需要调用者自己初始化,减少了写错密码等等这些错误。调用者只负责使用,不需要管怎么去创建、初始化对象。

还有,如果一个类有多个构造方法(构造的重写),我们也可以将它抽出来,放到工厂中,一个构造方法对应一个工厂方法并命名一个友好的名字,这样我们就不再只是根据参数的不同来判断,而是可以根据工厂的方法名来直观判断将要创建的对象的特点。这对于使用者来说,体验比较好。

工厂模式适用的一些场景(不仅限于以下场景):

  1. 对象的创建过程/实例化准备工作很复杂,需要初始化很多参数、查询数据库等。

2.类本身有好多子类,这些类的创建过程在业务中容易发生改变,或者对类的调用容易发生改变。

posted on 2022-03-21 22:15  曹操是个好同志  阅读(43)  评论(0编辑  收藏  举报