设计模式——工厂模式

设计模式——工厂模式

  1. 设计模式分为创建型、结构型、行为型三大类。
  2. 创建型设计模式主要解决“对象的创建”问题
    1. 比较常用的有单例模式和工厂模式,相关链接如下:
    2. 设计模式——单例模式
    3. 设计模式——工厂模式
  3. 结构型设计模式主要解决“类或对象的组合”问题
    1. 比较常用的有代理模式,装饰器模式,相关链接如下:
    2. 设计模式——代理模式
    3. 设计模式——装饰器模式
  4. 行为型设计模式主要解决的就是“类或对象之间的交互”问题
    1. 比较常用的有观察者模式,策略模式,模板模式
    2. 设计模式——观察者模式
    3. 设计模式——策略模式
    4. 设计模式——模板模式

目录

  1. 简单工厂
  2. 工厂方法
  3. 抽象工厂

工厂模式分为简单工厂、工厂方法和抽象工厂。

1. 简单工厂

1. 模式定义和使用场景

  1. 简单工厂模式又称为静态工厂方法模式,可以根据参数的不同返回不同类的实例,会专门定义一个类来负责创建其他类的实例。
    a. 比如根据配置文件的后缀(json、xml、yaml、properties),选择不同的解析器,将存储在文件中的配置解析成配置对象。
  2. 使用场景有:解析不同配置文件,获取不同加密算法的密钥生成器等。

2. 模式结构

  1. 简单工厂模式包含:
    a. Factory:工厂角色:负责实现创建所有实例
    b. Product:抽象产品角色:创建所有对象的父类,负责描述所有实例所共有的公共接口
    c. ConcreteProduct:具体产品角色:创建目标,某个具体类的实例。
    在这里插入图片描述

3. 简单工厂模式优点?

  1. 工厂类可以决定在什么时候创建产品类的实例,让使用者不需要直接创建产品对象,实现了对责任的分割。
  2. 使用者不需要知道创建的具体产品类的类名,只需要知道具体产品类所对应的参数就可以,减少了记忆量。
  3. 通过引入配置文件,可以在不修改任何代码的情况下更换和新增新的具体产品类,提供了系统灵活性。

4. 简单工厂模式缺点?

  1. 由于工厂类集中了所有产品创建逻辑,一旦出现问题,整个系统都要受到影响。
  2. 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
  3. 系统扩展困难,一旦添加新产品就要修改工厂逻辑,在产品类型较多时,可能造成工程逻辑过于复杂,不利于系统的扩展和维护。
  4. 由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

5. 简单工厂模式代码实现

1. C++代码实现
#include <iostream>
#include <vector>
#include "singleton.h"

using namespace std;

typedef enum ProductTypeTag {
    Hair,
    Hisense
} PRODUCTTYPETAG;

//抽象产品类 TV(电视机类)
class TV {
public:
    virtual void Show() = 0;
    virtual ~TV(){}; //声明析构函数为虚函数,防止内存泄漏
};

//具体产品类 HairTV(海尔电视类)
class HairTV : public TV {
public:
    void Show() {
        cout << "I'm HairTV " << endl;
    }
};

//具体产品类 HisenseTV(海信电视类)  
class HisenseTV : public TV {
public:
    void Show() {
        cout << "I'm HisenseTV" << endl;
    }
};

class TVFactory {
public:
    TV *CreateTV(PRODUCTTYPETAG type) {
        switch (type) {
            case Hair:
                return new HairTV();
            case Hisense:
                return new HisenseTV();
            default:
                return nullptr;
        }
    }
};

int main() {
    TVFactory *myTVFactory = new TVFactory();
    TV *hairTV = myTVFactory->CreateTV(Hair);
    if (hairTV != nullptr)
        hairTV->Show();

    TV *hisenseTV = myTVFactory->CreateTV(Hisense);
    if (hisenseTV != NULL)
        hisenseTV->Show();

    delete myTVFactory;
    myTVFactory = nullptr;

    delete hairTV;
    hairTV = NULL;

    delete hisenseTV;
    hisenseTV = NULL;

    return 0;
}
2. Go代码实现
package main

import (
	"fmt"
	"testing"
)

type Pay interface {
	Pay() string
}

type PayReq struct {
	OrderId string
}

type APayReq struct {
	PayReq
}

func (a *APayReq) Pay() string {
	//todo
	fmt.Println(a.OrderId)
	return "APay支付成功"
}

type BPayReq struct {
	PayReq
	Uid int64
}

func (b *BPayReq) Pay() string {
	// todo
	fmt.Println(b.OrderId)
	fmt.Println(b.Uid)
	return "BPay支付成功"
}

func TestPay(t *testing.T) {
	aPay := APayReq{}
	if aPay.Pay() != "APay支付成功" {
		t.Fatal("aPay error")
	}

	bPay := BPayReq{}
	if bPay.Pay() != "BPay支付成功" {
		t.Fatal("bPay error")
	}
}

2. 工厂方法

1. 模式定义和使用场景

  1. 简单工厂模式中最大的缺点是当有新产品要加入系统时,必须要修改工厂类,加入必要的处理逻辑,违背了“开闭原则”。
  2. 工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类负责生成具体的产品对象。目的是将产品的实例化操作延迟到工厂子类中完成,通过工厂子类来确定实例化哪一个具体产品类。
  3. 使用场景有:解析不同配置文件,获取不同加密算法的密钥生成器等。

2. 模式结构

  1. 工厂方法模式包含:
    a. Product:抽象产品:创建所有对象的父类,负责描述所有实例所共有的公共接口
    b. ConcreteProduct:具体产品:创建目标,某个具体类的实例。
    c. Factory:抽象工厂
    d. ConcreteFactory:具体工厂:是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,由使用者调用,返回一个具体产品类的实例。
    在这里插入图片描述

3. 工厂方法模式有哪些优点?

  1. 工厂方法用来创建用户所需要的产品同时还隐藏了哪种具体产品类将被实例化,用户只需要关心所需产品对应的工厂,不需要关心创建细节。
  2. 基于工厂角色和产品角色的多态性设计能够使工厂可以自主确定创建哪种产品对象,如何创建这个对象的细节又封装在具体工厂内部。
    a. 工厂方法模式又被称为多态工厂模式,因为所有的具体工厂类都有同一抽象父类。
  3. 工厂方法模式在系统中加入新产品时,不需要修改抽象工厂和抽象产品提供的接口,也不需要修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。
    a. 这样系统的可扩展性就变得非常好,完全符合“开闭原则”(对扩展开放,对修改关闭)。

4. 工厂方法模式有哪些缺点?

  1. 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
  2. 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性、理解难度和实现难度。

5. 工厂方法模式代码实现

1. C++代码实现
#include <iostream>
#include <vector>
#include "singleton.h"

using namespace std;

//抽象产品类 TV(电视机类)
class TV {
public:
    virtual void Show() = 0;

    virtual ~TV() {}; //声明析构函数为虚函数,防止内存泄漏
};

//具体产品类 HairTV(海尔电视类)
class HairTV : public TV {
public:
    void Show() {
        cout << "I'm HairTV " << endl;
    }
};

//具体产品类 HisenseTV(海信电视类)  
class HisenseTV : public TV {
public:
    void Show() {
        cout << "I'm HisenseTV" << endl;
    }
};

//工厂类(电视机工厂类)
class TVFactory {
public:
    virtual TV *CreateTV() = 0;

    virtual ~TVFactory() {};
};

//具体工厂类 HairTVFactory(海尔电视机工厂类)
class HairTVFactory : public TVFactory {
public:
    TV *CreateTV() {
        return new HairTV();
    }
};

//具体工厂类 HisenseTV(海信电视机工厂类)
class HisenseTVFactory : public TVFactory {
public:
    TV *CreateTV() {
        return new HisenseTV();
    }
};


int main() {
    TVFactory *hairTVFactory = new HairTVFactory();
    TV *hairTV = hairTVFactory->CreateTV();
    hairTV->Show();

    TVFactory *hisenseTVFactory = new HisenseTVFactory();
    TV *hisenseTV = hisenseTVFactory->CreateTV();
    hisenseTV->Show();

    if (hairTVFactory != NULL) {
        delete hairTVFactory;
        hairTVFactory = NULL;
    }

    if (hairTV != NULL) {
        delete hairTV;
        hairTV = NULL;
    }

    if (hisenseTVFactory != NULL) {
        delete hisenseTVFactory;
        hisenseTVFactory = NULL;
    }

    if (hisenseTV != NULL) {
        delete hisenseTV;
        hisenseTV = NULL;
    }

    return 0;
}

3. 抽象工厂

1. 模式定义和使用场景

  1. 在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,但是有时候需要一个工厂提供多个产品对象,就需要用到抽象工厂模式。
  2. 抽象工厂模式是工厂方法模式的泛化版,提供一个常见一系列相关对象的接口,而不需要指定具体的类,即一个具体的工厂可以生成多个具体产品。
    a. 比如海尔电器工厂可以生成海尔电视机、海尔电冰箱。

2. 模式结构

  1. 抽象工厂模式包含:
    a. AbstractProduct:抽象产品:创建所有对象的父类,负责描述所有实例所共有的公共接口
    b. Product:具体产品:创建目标,某个具体类的实例。
    c. AbstractFactory:抽象工厂
    d. ConcreteFactory:具体工厂:是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,由使用者调用,返回多个具体产品类的实例。
    在这里插入图片描述

3. 抽象工厂模式有哪些优点?

  1. 抽象工厂模式隔离了具体类的生成,更换一个具体工厂变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以改变整个软件系统的行为。
    a. 另外,抽象工厂模式可以实现高内聚低耦合的设计目的。
  2. 当一个产品族中的多个对象被设计在一起时,能够保证客户端始终只使用同一个产品族中的对象。
  3. 增加新的具体工厂和产品族很方便,不需要修改已有系统,符合“开闭原则”。

4. 抽象工厂模式有哪些缺点?

  1. 在添加新的产品对象时,要对抽象工厂的接口进行扩展,将涉及对抽象工厂角色及其所有子类的修改。
  2. 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。

5. 抽象工厂模式代码实现

1. C++代码实现
#include <iostream>
#include <vector>
#include "singleton.h"

using namespace std;

//抽象产品类 Television(电视机类)
class Television {
public:
    virtual void Show() = 0;

    virtual ~Television() {}; //声明析构函数为虚函数,防止内存泄漏
};

//具体产品类 HairTV(海尔电视类)
class HaierTelevision : public Television {
public:
    void Show() {
        cout << "I'm HaierTelevision" << endl;
    }
};

//具体产品类 HisenseTV(海信电视类)  
class TCLTelevision : public Television {
public:
    void Show() {
        cout << "I'm TCLTelevision" << endl;
    }
};

// 抽象产品类  AirCondition(空调类)
class AirCondition {
public:
    virtual void Show() = 0;

    virtual ~AirCondition() {};//析构函数声明为虚函数,防止内存泄漏
};

//具体产品类 HairAirCondition(海尔空调类)
class HairAirCondition : public AirCondition {
public:
    void Show() {
        cout << "I'm HairAirCondition" << endl;
    }
};

//具体产品类 TCLAirCondition(TCL空调
class TCLAirCondition : public AirCondition {
public:
    void Show() {
        cout << "I'm TCLAirCondition" << endl;
    }
};


//工厂类(电视机工厂类)
class EFactory {
public:
    virtual Television *CreateTelevision() = 0;

    virtual AirCondition *CreateAirCondition() = 0;

    virtual ~EFactory() {};
};

//具体工厂类 HairTVFactory(海尔电视机工厂类)
class HairFactory : public EFactory {
public:
    Television *CreateTelevision() {
        return new HaierTelevision();
    }

    AirCondition *CreateAirCondition() {
        return new HairAirCondition();
    }
};

//具体工厂类 TCLFactory(TCL工厂类) 
class TCLFactory : public EFactory {
public:
    Television *CreateTelevision() {
        return new TCLTelevision();
    }

    AirCondition *CreateAirCondition() {
        return new TCLAirCondition();
    }
};


int main() {
    EFactory *hairFactory = new HairFactory();
    Television *haierTelevision = hairFactory->CreateTelevision();
    AirCondition *haierAirCondition = hairFactory->CreateAirCondition();

    haierTelevision->Show();
    haierAirCondition->Show();

    EFactory *tCLFactory = new TCLFactory();
    Television *tCLTelevision = tCLFactory->CreateTelevision();
    AirCondition *tCLAirCondition = tCLFactory->CreateAirCondition();

    tCLTelevision->Show();
    tCLAirCondition->Show();

    if (hairFactory != NULL) {
        delete hairFactory;
        hairFactory = NULL;
    }

    if (haierTelevision != NULL) {
        delete haierTelevision;
        haierTelevision = NULL;
    }

    if (tCLAirCondition != NULL) {
        delete tCLAirCondition;
        tCLAirCondition = NULL;
    }

    if (tCLFactory != NULL) {
        delete tCLFactory;
        tCLFactory = NULL;
    }

    if (tCLTelevision != NULL) {
        delete tCLTelevision;
        tCLTelevision = NULL;
    }

    if (tCLAirCondition != NULL) {
        delete tCLAirCondition;
        tCLAirCondition = NULL;
    }

    return 0;
}
2. Go代码实现
package main

import "fmt"

// SaveArticle 抽象模式工厂接口
type SaveArticle interface {
    CreateProse() Prose
    CreateAncientPoetry() AncientPoetry
}

type SaveRedis struct{}

func (*SaveRedis) CreateProse() Prose {
    return &RedisProse{}
}

func (*SaveRedis) CreateAncientPoetry() AncientPoetry {
    return &RedisProse{}
}

type SaveMysql struct{}

func (*SaveMysql) CreateProse() Prose {
    return &MysqlProse{}
}

func (*SaveMysql) CreateAncientPoetry() AncientPoetry {
    return &MysqlProse{}
}

// Prose 散文
type Prose interface {
    SaveProse()
}

// AncientPoetry 古诗
type AncientPoetry interface {
    SaveAncientPoetry()
}

type RedisProse struct{}

func (*RedisProse) SaveProse() {
    fmt.Println("Redis Save Prose")
}

func (*RedisProse) SaveAncientPoetry() {
    fmt.Println("Redis Save Ancient Poetry")
}

type MysqlProse struct{}

func (*MysqlProse) SaveProse() {
    fmt.Println("Mysql Save Prose")
}

func (*MysqlProse) SaveAncientPoetry() {
    fmt.Println("Mysql Save Ancient Poetry")
}

func Save(saveArticle SaveArticle) {
    saveArticle.CreateProse().SaveProse()
    saveArticle.CreateAncientPoetry().SaveAncientPoetry()
}

func ExampleSaveRedis() {
    var factory SaveArticle
    factory = &SaveRedis{}
    Save(factory)
    // Output:
    // Redis Save Prose
    // Redis Save Ancient Poetry
}

func ExampleSaveMysql() {
    var factory SaveArticle
    factory = &SaveMysql{}
    Save(factory)
    // Output:
    // Mysql Save Prose
    // Mysql Save Ancient Poetry
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值