精华内容
下载资源
问答
  • 本系列文章是希望将软件项目中最常见的设计模式用通俗易懂的语言来讲解清楚,并通过Python来...理解了为什么我们也就基本了解了什么情况下使用这个模式,不过在这里还是会细化使用场景,阐述模式的局限优缺点。这...

    本系列文章是希望将软件项目中最常见的设计模式用通俗易懂的语言来讲解清楚,并通过Python来实现,每个设计模式都是围绕如下三个问题:

    为什么?即为什么要使用这个设计模式,在使用这个模式之前存在什么样的问题?

    是什么?通过Python语言来去实现这个设计模式,用于解决为什么中提到的问题。

    怎么用?理解了为什么我们也就基本了解了什么情况下使用这个模式,不过在这里还是会细化使用场景,阐述模式的局限和优缺点。

    这次的主角是简单工厂,工厂方法和抽象工厂模式,由于这几个模式联系紧密,有一定的相似性,所以放在一起来讲。

    简单工厂模式

    为什么

    工厂模式里最常举的例子就是Pizza店的例子,我们就用这个经典的例子来说吧。假设我们开了一个Pizza店,然后我们多种Pizza供顾客选用,如下:

    class CheesePizza(object):

    ...

    class VegetablePizza(object):

    ...

    # 可以继续定义多种类型的Pizza

    ...

    然后可以定义我们的Pizza店用以生产Pizza

    class PizzaStore(object):

    def order_pizza(self, pizza_type):

    # ------------------------------------

    if pizza_type == "cheese":

    self.pizza = CheesePizza()

    elif pizza_type == "vegetable":

    self.pizza = VegetablePizza()

    else:

    self.pizza = SeafoodPizza()

    # -------------------------------------

    self.pizza.prepare()

    self.pizza.bake()

    self.pizza.cut()

    self.pizza.box()

    return self.pizza

    这里问题在于我们的产品(也就是不同种类的Pizza)可能会变化,比如过了段时间会新增几种类型的Pizza,也会去掉某些不受欢迎的Pizza类型,这个时候我们就需要修改不断修改order_pizza()中的代码(横线包起来的那部分代码)。而我们的设计原则之一就是将“变化”抽离出来,进行封装。这就是简单工厂模式的初衷。

    是什么

    简单工厂模式,就是将创建不同类型实例的代码抽离出来,封装成一个工厂类(实际我觉得用一个函数更直接)。这个工厂类就是专门用于生产不同的产品(这里就是pizza产品)给客户端(这里就是order_pizza)。客户不需要知道怎么生产出这些pizza,客户只需要告诉工厂,我需要cheese pizza还是其它类型的pizza就可以了,然后工厂会去返回给客户相应的pizza。代码如下:

    class SimplePizzaFactory(object):

    @staticmethod

    def create_pizza(pizza_type):

    # 实际应用中,我们还可以通过配置文件以及反射机制来实现create_pizza, 这样的话当有新的pizza类型加入的时候,只需要更改配置文件即可

    pizzas = dict(cheese=CheesePizza, vegetable=VegetablePizza, seafood=SeafoodPizza)

    return pizzas[pizza_type]()

    原来的PizzaStore则更改为:

    class PizzaStore(object):

    def order_pizza(self, pizza_type):

    # ------------------------------------

    self.pizza = SimplePizzaFactory.create_pizza(pizza_type)

    # -------------------------------------

    self.pizza.prepare()

    self.pizza.bake()

    self.pizza.cut()

    self.pizza.box()

    return self.pizza

    怎么用

    看到上边的代码,很多同学可能会疑惑,这个就是代码转移到别处而已,似乎没有什么卵用啊。其实简单工厂模式除了将创建实例的代码进行了封装,使得代码更加清晰以外,另一个好处就是,当有其它客户需要创建同样的实例时就可以直接调用工厂的create_pizza()了。比如我们有了一个送外卖的类:

    class PizzaTakeOut(object):

    def order_pizza(self, pizza_type):

    # ------------------------------------

    self.pizza = SimplePizzaFactory.create_pizza(pizza_type)

    # -------------------------------------

    ...

    在这种情况下,如果新增或者删除某一个产品(Pizza类)我们只需要简单地更新一处代码(即简单工厂中的创建实例的代码)就可以了。

    再一个好处是,一个大的系统往往是分不同的层次和模块进行分别开发的,当开发客户端(这里就是指PizzaStore)程序员和开发底层产品(这里指各种Pizza)的程序员不是同一个人就会非常有用,因为开发客户端的程序员通过工厂创建对象时就不需要关注到底怎么创建出不同的产品的,他只需要将客户的需求(pizza_type)传递给工厂就可以了。

    工厂方法和抽象工厂模式

    为什么?

    在简单工厂中我们一般情况下只是创建了一种产品,但是对于一组产品的创建,往往很难应付,想想下如果我们要创建一组关于汽车的零部件产品,如果用简单工厂模式,代码可能如下:

    class SimpleCarPartsFactory(object):

    def __init__(self, car_type):

    self.car_type = car_type

    def create_engines(self):

    engines = dict(small=SmallEngines, medium=MediumEngines, big=BigEngines)

    return engines[self.car_type]()

    def create_wheels(self):

    wheels = dict(small=SmallWheeles, medium=MediumWheeles, big=BigWheeles)

    return wheels[self.car_type]()

    ...

    这个代码虽然也可以勉强使用,但是试想一下,如果我再添加一个superbig类型的汽车,那么是不是就需要修改所有的create方法?如果修改某个组件类,或者删除某一种类型的组件是否都需要去修改这个类呢?如果这些都是你一个人来改呢?。。。。。。

    好吧,这就是我们为什么需要工厂方法和抽象工厂的原因。

    是什么

    首先来说下什么是工厂方法,工厂方法就是将客户端程序抽象出一个父类,然后在子类中实现创建产品的方法,这个方法就是工厂方法

    class PizzaStore(object): # 客户端程序抽象出父类

    def order_pizza(self, pizza_type):

    # ------------------------------------

    self.pizza = self.create_pizza(pizza_type)

    # -------------------------------------

    self.pizza.prepare()

    self.pizza.bake()

    self.pizza.cut()

    self.pizza.box()

    return self.pizza

    def create_pizza(self, pizza_type): #抽象的工厂方法

    pass

    class BeijingPizzaStore(PizzaStore): # 客户端程序的子类

    def create_pizza(self, pizza_type): # 具体的工厂方法

    pizzas = dict(cheese=BeijingCheesePizza, vegetable=BeijingVegetablePizza, seafood=BeijingSeafoodPizza) # 不同的子类可能使用不同的产品

    return pizzas[pizza_type]()

    class ShanghaiPizzaStore(PizzaStore):

    def create_pizza(self, pizza_type):

    pizzas = dict(cheese=ShanghaiCheesePizza, vegetable=ShanghaiVegetablePizza, seafood=ShanghaiSeafoodPizza)

    return pizzas[pizza_type]()

    这里如果我们用简单工厂模式去实现的话,就要给create方法多传递一个地区的参数(如:"beijing"),然后在方法中要做两次条件判断(地区和pizza类型),这样做就有点不太优雅了。

    这里实际也体现了软件设计的原则,将变化的地方通过抽象/继承来封装,由于会有"不同"种类的产品,所以就会有"不同"的create_pizza,那么我们就可以将PizzaStore抽象出来,通过继承的方式实现"不同"的create_pizza工厂方法

    不论怎么样,我们现在已经了解了什么是工厂方法模式,那么现在要看另一个设计模式-抽象工厂模式,这个模式中实际使用了工厂方法模式。而抽象工厂模式才是真正解决了我们之前说的一组产品的问题。

    使用抽象工厂来实现汽车组件的实例生产:

    class AbstractCarPartsFactory(object): #Python中这个抽象类甚至可以省略,但是为了表达清晰,还是创建了这个父类

    def create_engine(self):

    passs

    def create_wheels(self):

    pass

    ...

    class SmallCarPartsFactory(AbstractCarPartsFactory): #不同类型的汽车工厂维护自身的实例创建

    def create_engine(self): #具体的工厂方法

    return SmallEngine()

    def create_wheels(self):

    return SmallWheels()

    ...

    class MediumCarPartsFactory(AbstractCarPartsFactory):

    def create_engine(self):

    return SmallEngine()

    def create_wheels(self):

    return SmallWheels()

    ...

    ...

    使用时如下:

    class CarFactory(object):

    def create_car(self, car_type):

    car_factorys = dict(

    'small'=SmallCarPartsFactory, 'medium'=MediumCarPartsFactory,

    'big'=BigCarPartsFactory)

    self.carparts_factory = car_factorys[car_type]()

    self.prepare_parts():

    self.engine = self.cartparts_factory.create_engine()

    self.wheels = self.cartparts_factory.create_wheels()

    ...

    self.compose_parts()

    self.painting()

    ...

    由以上例子可以看出我们首先将生产一组产品的工厂抽象成一个工厂类(即,AbstractCarPartsFactory),这正是抽象工厂这个名字的由来。随后我们通过不同子类工厂来实现具体产品的实例化,在子类中实现产品实例化,是不是听着耳熟,对,这里正是利用了工厂方法模式,所以抽象工厂模式利用了工厂方法模式,但它们却是不同的模式,这里注意区分。

    这时,如果我们想增加一个新的汽车类型,那么只需要添加一个子类即可,是不是很轻松的赶脚?

    怎么用

    总结下,所谓工厂就是用于生产产品(也就是创建实例),当我们只有一种产品时我们其实是不需要工厂的,只有在有多种类型的产品的时候才需要工厂来帮我们选择特定的类去实例化。

    一般的简单使用场景,简单工厂模式足以应付。当我们需要对一组产品同时初始化,并且每个产品都有多种类型的时候,就需要抽象工厂模式来应付了(个人以为工厂方法模式单独使用效果并不明显,但是在抽象工厂模式中却能最大化发挥价值)。

    总之,当你有很多产品需要实例化时,考虑下工厂模式吧!

    展开全文
  • 工厂方法抽象工厂方法: 图示: 区别: 联系:

    区别:工厂方法里面产品分为抽象基类和一个具体实现的子类;而抽象工厂将具体实现子类进行了模块化的细分,有多个抽象产品类 ,具体工厂类能创建多个具体产品类的实例。

     

    我从一下几个方面来理解抽象工厂和工厂方法不同点

    • 抽象工程关键在于产品之间的抽象关系,所以至少要两个产品;工厂方法在于生成产品,不关注产品间的关系,所以可以只生成一个产品。
    • 抽象工厂中客户端把产品的抽象关系理清楚,在最终使用的时候,一般使用客户端(和其接口),产品之间的关系是被封装固定的;而工厂方法是在最终使用的时候,使用产品本身(和其接口)。

    抽象工厂更像一个复杂版本的策略模式,策略模式通过更换策略来改变处理方式或者结果;而抽象工厂的客户端,通过更改工厂还改变结果。所以在使用的时候,就使用客户端和更换工厂,而看不到产品本身。

    工厂方法目的是生产产品,所以能看到产品,而且还要使用产品。当然,如果产品在创建者内部使用,那么工厂方法就是为了完善创建者,从而可以使用创建者。另外创建者本身是不能更换所生产产品的。

     

    • 抽象工厂的工厂是类;工厂方法的工厂是方法。

    抽象工厂的工厂类就做一件事情生产产品。生产的产品给客户端使用,绝不给自己用。
    工厂方法生产产品,可以给系统用,可以给客户端用,也可以自己这个类使用。自己这个类除了这个工厂方法外,还能有其他功能性的方法


    其实仔细想想,这个两个模式是有交集的,在极端的情况下,这两个模式其实是一样的。所以可以这样理解

    • 给工厂方法模式加一个客户端,除了客户端都不用这个创建者。这个时候创建者就是工厂类了。(单一产品的特定关系这个时候就是没有关系)
    • 抽象工厂模式中,在客户端内部编程时候,就可以把工厂类当作创建者。
    展开全文
  • 工厂方法和抽象工厂

    2021-02-25 21:02:14
    工厂方法和抽象工厂工厂方法 工厂方法 首先看一下为什么需要工厂方法: class ISplitter{ public: virtual void split()=0; virtual ~ISplitter(){} }; class BinarySplitter : public ISplitter{ }; class ...

    工厂方法和抽象工厂

    工厂方法

    首先看一下为什么需要工厂方法:

    class ISplitter{
    public:
        virtual void split()=0;
        virtual ~ISplitter(){}
    };
    
    class BinarySplitter : public ISplitter{
        
    };
    
    class TxtSplitter: public ISplitter{
        
    };
    
    class PictureSplitter: public ISplitter{
        
    };
    
    class VideoSplitter: public ISplitter{
        
    };
    
    class MainForm : public Form
    {
    	TextBox* txtFilePath;
    	TextBox* txtFileNumber;
    	ProgressBar* progressBar;
    
    public:
    	void Button1_Click(){
    		ISplitter * splitter=
                new BinarySplitter();//依赖具体类
            splitter->split();
    
    	}
    };
    

    上面的代码还是来实现文件分割器的,txtFilePath代表文件路径,txtFileNumber代表要分给文件的数量,分割器splitter依赖于具体的实现类BinarySplitter,这种依赖是编译时依赖,我们解除这种依赖关系,看下面的改造。

    //抽象类
    class ISplitter{
    public:
        virtual void split()=0;
        virtual ~ISplitter(){}
    };
    
    
    //工厂基类
    class SplitterFactory{
    public:
        virtual ISplitter* CreateSplitter()=0;
        virtual ~SplitterFactory(){}
    };
    
    //具体类
    class BinarySplitter : public ISplitter{
        
    };
    
    class TxtSplitter: public ISplitter{
        
    };
    
    class PictureSplitter: public ISplitter{
        
    };
    
    class VideoSplitter: public ISplitter{
        
    };
    
    //具体工厂
    class BinarySplitterFactory: public SplitterFactory{
    public:
        virtual ISplitter* CreateSplitter(){
            return new BinarySplitter();
        }
    };
    
    class TxtSplitterFactory: public SplitterFactory{
    public:
        virtual ISplitter* CreateSplitter(){
            return new TxtSplitter();
        }
    };
    
    class PictureSplitterFactory: public SplitterFactory{
    public:
        virtual ISplitter* CreateSplitter(){
            return new PictureSplitter();
        }
    };
    
    class VideoSplitterFactory: public SplitterFactory{
    public:
        virtual ISplitter* CreateSplitter(){
            return new VideoSplitter();
        }
    };
    
    class MainForm : public Form
    {
        SplitterFactory*  factory;//工厂
    
    public:
        
        MainForm(SplitterFactory*  factory){
            this->factory=factory;
        }
        
    	void Button1_Click(){
    
            
    		ISplitter * splitter=
                factory->CreateSplitter(); //多态new
            
            splitter->split();
    
    	}
    };
    

    上面的代码可以看出现在分割器的产生就没有依赖某个具体的类,而是依赖于一个抽象的工厂类,通过运行时多态的方式来
    产生不同的对象。避免了编译时的依赖某个具体的类,也提高了程序的扩展性。

    抽象工厂

    class EmployeeDAO{
        
    public:
        vector<EmployeeDO> GetEmployees(){
            SqlConnection* connection =
                new SqlConnection();
            connection->ConnectionString = "...";
    
            SqlCommand* command =
                new SqlCommand();
            command->CommandText="...";
            command->SetConnection(connection);
    
            SqlDataReader* reader = command->ExecuteReader();
            while (reader->Read()){
    
            }
    
        }
    };
    

    上面的代码是常用的连接数据库的相关代码,假设现在我们要支持多种数据库的访问。看下的代码是否满足需求。

    //数据库访问有关的基类
    class IDBConnection{
        
    };
    class IDBConnectionFactory{
    public:
        virtual IDBConnection* CreateDBConnection()=0;
    };
    
    
    class IDBCommand{
        
    };
    class IDBCommandFactory{
    public:
        virtual IDBCommand* CreateDBCommand()=0;
    };
    
    
    class IDataReader{
        
    };
    class IDataReaderFactory{
    public:
        virtual IDataReader* CreateDataReader()=0;
    };
    
    
    //支持SQL Server
    class SqlConnection: public IDBConnection{
        
    };
    class SqlConnectionFactory:public IDBConnectionFactory{
        
    };
    
    
    class SqlCommand: public IDBCommand{
        
    };
    class SqlCommandFactory:public IDBCommandFactory{
        
    };
    
    
    class SqlDataReader: public IDataReader{
        
    };
    class SqlDataReaderFactory:public IDataReaderFactory{
        
    };
    
    //支持Oracle
    class OracleConnection: public IDBConnection{
        
    };
    
    class OracleCommand: public IDBCommand{
        
    };
    
    class OracleDataReader: public IDataReader{
        
    };
    
    
    
    class EmployeeDAO{
        IDBConnectionFactory* dbConnectionFactory;
        IDBCommandFactory* dbCommandFactory;
        IDataReaderFactory* dataReaderFactory;
        
        
    public:
        vector<EmployeeDO> GetEmployees(){
            IDBConnection* connection =
                dbConnectionFactory->CreateDBConnection();
            connection->ConnectionString("...");
    
            IDBCommand* command =
                dbCommandFactory->CreateDBCommand();
            command->CommandText("...");
            command->SetConnection(connection); //关联性
    
            IDBDataReader* reader = command->ExecuteReader(); //关联性
            while (reader->Read()){
    
            }
    
        }
    };
    
    

    这里在使用之前肯定是要先初始化dbConnectionFactory,dbCommandFactory,dataReaderFactory这三个指针,看着好像是没有问题,但是不同数据库的Connection,Command,Reader是绑定在一起的,不同数据库的是不能混用的,所以还是有一点小缺陷。

    
    //数据库访问有关的基类
    class IDBConnection{
        
    };
    
    class IDBCommand{
        
    };
    
    class IDataReader{
        
    };
    
    
    class IDBFactory{
    public:
        virtual IDBConnection* CreateDBConnection()=0;
        virtual IDBCommand* CreateDBCommand()=0;
        virtual IDataReader* CreateDataReader()=0;
        
    };
    
    
    //支持SQL Server
    class SqlConnection: public IDBConnection{
        
    };
    class SqlCommand: public IDBCommand{
        
    };
    class SqlDataReader: public IDataReader{
        
    };
    
    
    class SqlDBFactory:public IDBFactory{
    public:
        virtual IDBConnection* CreateDBConnection()=0;
        virtual IDBCommand* CreateDBCommand()=0;
        virtual IDataReader* CreateDataReader()=0;
     
    };
    
    //支持Oracle
    class OracleConnection: public IDBConnection{
        
    };
    
    class OracleCommand: public IDBCommand{
        
    };
    
    class OracleDataReader: public IDataReader{
        
    };
    
    
    
    class EmployeeDAO{
        IDBFactory* dbFactory;
        
    public:
        vector<EmployeeDO> GetEmployees(){
            IDBConnection* connection =
                dbFactory->CreateDBConnection();
            connection->ConnectionString("...");
    
            IDBCommand* command =
                dbFactory->CreateDBCommand();
            command->CommandText("...");
            command->SetConnection(connection); //关联性
    
            IDBDataReader* reader = command->ExecuteReader(); //关联性
            while (reader->Read()){
    
            }
    
        }
    };
    
    

    上面一段代码就很好的解决这个问题看,对具体的工厂类再进行一次抽象,就可以解决工厂类之间存在相互联系的问题。

    展开全文
  • Factory Method工厂方法和 Abstract Factory 抽象工厂

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

    1. Factory Method工厂方法

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

    class FileSplitter
    {
    	//...
    	void split(){
    		//...
    	}
    };
    class MainForm : public Form
    {
    	//...
    public:
    	void Button1_Click(){
    
    		string filePath = txtFilePath->getText();
    		int number = atoi(txtFileNumber->getText().c_str());
    
    		FileSplitter* splitter = new FileSplitter(); //应该声明为抽象类,而不是具体的类型
    
    		splitter->split();
    
    	}
    };
    

    在上面代码中,实现了文件分割器。一个类型,要看到未来变化的需求。这是就要做抽象类,即面向接口的编程。一个对象的类型,往往应该声明为抽象类或者接口,而不应该声明成具体的类。如果声明为具体类型,就定死了,不能应对未来的变化。
    假设还要支持文本分割TxtSplitter()、图片分割PictureSplitter()等等。抽象出一个基类ISplitter()。

    class ISplitter{ // 抽象基类
    public:
        virtual void split()=0;
        virtual ~ISplitter(){}
    };
    
    class BinarySplitter : public ISplitter{
        
    };
    
    class TxtSplitter: public ISplitter{
        
    };
    
    class PictureSplitter: public ISplitter{
        
    };
    
    class MainForm : public Form
    {
    	TextBox* txtFilePath;
    	TextBox* txtFileNumber;
    	ProgressBar* progressBar;
    
    public:
    	void Button1_Click(){
            //...
    		ISplitter * splitter=  // 使用抽象类
    			new BinarySplitter();//依赖具体类
            
            splitter->split();
    	}
    };
    

    虽然使用了抽象类型进行变量的声明,但是使用 new 创建对象时仍然依赖具体类。既然不能使用new创建对象,那能不能创建一种方法使它返回一个对象呢?

    //抽象类
    class ISplitter{
    public:
        virtual void split()=0;
        virtual ~ISplitter(){}
    };
    
    
    //工厂基类
    class SplitterFactory{
    public:
        virtual ISplitter* CreateSplitter()=0;
        virtual ~SplitterFactory(){}
    };
    
    
    //具体类
    class BinarySplitter : public ISplitter{
        
    };
    
    class TxtSplitter: public ISplitter{
        
    };
    
    class PictureSplitter: public ISplitter{
        
    };
    
    
    //具体工厂,每一个类都有对应的工厂
    class BinarySplitterFactory: public SplitterFactory{
    public:
        virtual ISplitter* CreateSplitter(){
            return new BinarySplitter();
        }
    };
    
    class TxtSplitterFactory: public SplitterFactory{
    public:
        virtual ISplitter* CreateSplitter(){
            return new TxtSplitter();
        }
    };
    
    class PictureSplitterFactory: public SplitterFactory{
    public:
        virtual ISplitter* CreateSplitter(){
            return new PictureSplitter();
        }
    };
    
    
    class MainForm : public Form
    {
        SplitterFactory*  factory;//工厂
    
    public:
        
        MainForm(SplitterFactory*  factory){ // 从外界传递具体的SplitterFactory类型
            this->factory=factory;
        }
        
    	void Button1_Click(){
            
    		ISplitter * splitter=
                factory->CreateSplitter(); //多态new
            
            splitter->split();
    
    	}
    };
    

    改良之后,MainForm已经不依赖具体类了。MainForm依赖于抽象类和工厂基类,而不依赖于具体类和具体工厂。

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

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

    2. Abstract Factory 抽象工厂

    动机(Motivation)
    在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。
    如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合?

    代码示例
    数据访问层,要创建一系列的对象。假设访问的是SQLSever的数据库,则要创建链接对象SqlConnection,命令对象SqlCommand,SqlDataReader对象。但数据库有各种各样的选择,可能后面又要使用MySQL。

    class EmployeeDAO{
        
    public:
        vector<EmployeeDO> GetEmployees(){
            SqlConnection* connection =
                new SqlConnection();
            connection->ConnectionString = "...";
    
            SqlCommand* command =
                new SqlCommand();
            command->CommandText="...";
            command->SetConnection(connection);
    
            SqlDataReader* reader = command->ExecuteReader();
            while (reader->Read()){
    
            }
    
        }
    };
    
    

    为访问多种数据库,创建数据库访问相关的基类。因为上面代码使用new创建对象,使用工厂模式,代码如下。

    
    //数据库访问有关的基类
    class IDBConnection{// 基类
        
    };
    class IDBConnectionFactory{ // 工厂基类
    public:
        virtual IDBConnection* CreateDBConnection()=0;
    };
    
    class IDBCommand{ // 基类
        
    };
    class IDBCommandFactory{ // 工厂基类
    public:
        virtual IDBCommand* CreateDBCommand()=0;
    };
    
    class IDataReader{ //基类
        
    };
    class IDataReaderFactory{ //工厂基类
    public:
        virtual IDataReader* CreateDataReader()=0;
    };
    
    
    //支持SQL Server
    class SqlConnection: public IDBConnection{ // 具体类
        
    };
    class SqlConnectionFactory:public IDBConnectionFactory{ //具体工厂
        
    };
    
    class SqlCommand: public IDBCommand{
        
    };
    class SqlCommandFactory:public IDBCommandFactory{
        
    };
    
    class SqlDataReader: public IDataReader{
        
    };
    class SqlDataReaderFactory:public IDataReaderFactory{
        
    };
    
    //支持Oracle
    class OracleConnection: public IDBConnection{
        
    };
    
    class OracleCommand: public IDBCommand{
        
    };
    
    class OracleDataReader: public IDataReader{
        
    };
    
    
    
    class EmployeeDAO{
        IDBConnectionFactory* dbConnectionFactory;
        IDBCommandFactory* dbCommandFactory;
        IDataReaderFactory* dbCommandFactory;
        
        // 构造函数,传入具体类型
    public:
        vector<EmployeeDO> GetEmployees(){
            IDBConnection* connection =
                dbConnectionFactory->CreateDBConnection();
            connection->ConnectionString("...");
    
            IDBCommand* command =
                dbCommandFactory->CreateDBCommand();
            command->CommandText("...");
            command->SetConnection(connection); //关联性,命令和连接是相关的对象
    
            IDBDataReader* reader = command->ExecuteReader(); //关联性
            while (reader->Read()){
    
            }
    
        }
    };
    
    

    上面代码涉及多个基类(IDBConnection、IDBCommand、IDataReader),要为每个基类都设计一个对应的工厂基类(IDBConnectionFactory、IDBCommandFactory、IDataReaderFactory)。
    上面代码基本解决了问题,但是还有缺陷:在EmployeeDAO中,成员dbConnectionFactory、dbCommandFactory、dbCommandFactory是有关联性的,所以要么都是SQL,要么都是Oracle,不能有的是SQL,有的是Oracle.不能建立了SQL的connection,有创建了Oracle的commend。

    //数据库访问有关的基类
    class IDBConnection{
        
    };
    
    class IDBCommand{
        
    };
    
    class IDataReader{
        
    };
    
    class IDBFactory{ // 使用一个工厂
    public:
        virtual IDBConnection* CreateDBConnection()=0;
        virtual IDBCommand* CreateDBCommand()=0;
        virtual IDataReader* CreateDataReader()=0;
        
    };
    
    //支持SQL Server
    class SqlConnection: public IDBConnection{ //具体类
        
    };
    class SqlCommand: public IDBCommand{
        
    };
    class SqlDataReader: public IDataReader{
        
    };
    
    class SqlDBFactory:public IDBFactory{ // 具体工厂
    public:
        virtual IDBConnection* CreateDBConnection()=0;
        virtual IDBCommand* CreateDBCommand()=0;
        virtual IDataReader* CreateDataReader()=0;
     
    };
    
    //支持Oracle
    class OracleConnection: public IDBConnection{
        
    };
    
    class OracleCommand: public IDBCommand{
        
    };
    
    class OracleDataReader: public IDataReader{
        
    };
    
    
    class EmployeeDAO{
        IDBFactory* dbFactory;
        
    public:
        vector<EmployeeDO> GetEmployees(){
            IDBConnection* connection =
                dbFactory->CreateDBConnection();
            connection->ConnectionString("...");
    
            IDBCommand* command =
                dbFactory->CreateDBCommand();
            command->CommandText("...");
            command->SetConnection(connection); //关联性
    
            IDBDataReader* reader = command->ExecuteReader(); //关联性
            while (reader->Read()){
    
            }
    
        }
    };
    

    模式定义
    提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。

    在这里插入图片描述
    要点总结
    如果没有应对“多系列对象构建”的需求变化,则没有必要使用Abstract Factory模式,这时候使用简单的工厂完全可以。
    “系列对象”指的是在某一特定系列下的对象之间有相互依赖、或作用的关系。不同系列的对象之间不能相互依赖。
    Abstract Factory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。
    例如,上面示例中,可以很好支持各种数据库,但如果要加一个新对象的话,就要在抽象工厂基类中添加新的对象,使稳定的内容发生了变化。

    展开全文
  • 在前面的学习中(参见前面的博客),我们学到了很多OO原则:封装变化多用组合,少用继承针对接口/超类编程,不针对实现编程松耦合开闭原则让我们从一个简单的类开始,看看如何将之改造成符合OO原则的类以及工厂模式在...
  • 文章目录一、工厂方法1、工厂法法模式结构图:2、工厂方法模式的优缺点二、抽象工厂模式1、抽象工厂模式结构图2、抽象工厂模式的优缺点 一、工厂方法 工厂方法定义:定义一个用于创建对象的接口,让子类决定实例化哪...
  • 在前面的学习中(参见前面的博客),我们学到了很多OO原则:封装变化多用组合,少用继承针对接口/超类编程,不针对实现编程松耦合开闭原则让我们从一个简单的类开始,看看如何将之改造成符合OO原则的类以及工厂模式在...
  • 设计模式概念 设计模式简单来说就是在解决某一类问题场景时,有既定的,优秀的代码框架可以直接使用,与我们自己摸索出来的问题解决之道相...根据上面的内容描述,仔细思考简单工厂,工厂方法和抽象工厂的区别联系。
  • 工厂方法模式:定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。类型:创建类模式类图:类图知识点:1.类图分为三部分,依次是类名、属性、方法2.以<>...
  • 抽象工厂模式 1 工厂:产品 = 1:N 工厂:产品 = 1:1 工厂:产品 = 1:N 2 一个工厂类 一个抽象产品类,多个具体产品类 一个抽象工厂类,多个具体工厂类 一个...
  • 工厂模式通常分为简单工厂、工厂方法和抽象工厂三种,看了不少资料,好多讲的都是云里雾里的。要么是概念太多,让人看得一脸懵逼,要么是举得例子不太恰当,看了更让人迷惑了。通过本身一番研究,经过一个简单的例子...
  • 工厂模式将目的将创建对象的具体过程屏蔽隔离起来,从而达到更高的灵活性,工厂模式可以分为三类:简单工厂模式、工厂方法模式、抽象工厂模式;简单工厂模式的核心是定义一个创建对象的接口,将对象的创建本身的...
  • 创建型模式关注对象的创建过程,它将对象的创建使用分离,在使用对象时无须知道对象的创建细节。这样可以降低系统的耦合度。使得相同的创建过程可以多次复用,且修改二者中的一个对另一个几乎不造成任何影响或很少的...
  • 2.抽象产品:抽象类、接口 3.产品簇: 4.产品等级: 简单工厂: 这种设计相当脆弱!为什么呢?因为,只要作者修改了具体产品的类名,那么,客户端代码也要随之一起改变,这样,服务器端代码客户端代码就是耦合的...
  • 目前工厂模式大致分为3种,分别是:简单工厂模式、工厂方法模式、抽象工厂模式
  • 之前写过一篇关于工厂模式(Factory Pattern)的随笔,里面分析了简单工厂模式,但对于工厂方法和抽象工厂的分析较为简略。这里重新分析分析三者的区别,工厂模式是java设计模式中比较简单的一个设计模式,但很多地方...
  • 3.如果要扩大后花园的规模,比如一个在北方,一个在南方,这样工厂方法就无法实现了,就应当用抽象工厂,把各种各样的植物,又组成一个后花园. 所以我个人认为,简单工厂是一个工厂只生产一类的产品,面对的是具体的类,工厂...
  • 当需要增加一种对象,只需要增加产品类,并在工厂中增加创建实体代码,但不符合开闭原则)1 工厂类角色:这是本模式的核心,含有一定的商业逻辑判断逻辑,根据逻辑不同,产生具体的工厂产品。如例子中的...
  • 一、简单工厂模式 例如:一个动物基类(抽象基类):描述什么是动物 N个动物类(继承抽象类):具体是什么动物,狗猫兔 一个工厂(根据不同条件生成创建不同动物): ...一个抽象工厂接口(接口) 创建生产动物的工厂实现类(实
  • 1.简单工厂模式:简单工厂模式属于类的创建型模式,又叫做静态工厂模式。...2.抽象角色。简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。3.具体产品角色。简单工厂模...
  • 简单工厂、工厂方法抽象工厂三种设计模式都属于创建型设计模式,根据作用范围划分,简单工厂、工厂方法属于类模式;抽象工厂属于对象模式;由于简单工厂只是对类的创建进行同一的管理(用工厂类进行抉择创建什么...
  • 设计模式之Factory工厂模式定义:提供创建对象的接口.为何使用?工厂模式是我们最常用的模式了,著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。为什么工厂模式是如此常用?因为工厂...
  • 简单工厂模式,工厂方法模式,抽象工厂模式(从放弃到入门)@(设计模式)工厂模式,很多讲设计模式的书中,工厂模式都是第一个讲的模式,因为其最简单。但是在实际开发中,工厂模式是非常常见的。在Java开发中经常遇到...
  • 工厂模式 定义一个用于创建对象的接口,让...工厂方法模式,是典型的解耦框架。高层模块只需要知道产品的抽象类,符合迪米特法则。也符合依赖倒置原则,只依赖产品抽象类。也符合里氏替换原则,使用产品子类替换父产
  • 3)抽象工厂模式(Abstract Factory) 简单工厂: 定义:是由一个工厂对象决定创建出哪一种产品类的实例。 简单工厂模式中包含的角色及其相应的职责如下: 工厂角色(Creator):这是简单工厂模式的核心,由它负责...
  • 工厂方法模式实现步骤(1)创建手机工厂对象(2)创建工厂方法接口(3)实现工厂对象(4)实现工厂方法(5)创建订单类并测试结果(6) 新增手机类别(7) 新增手机工厂(8) 测试结果3. 工厂方法模式的设计原理4. ...
  • 抽象工厂模式简单工厂模式1.1. 模式动机考虑一个简单的软件应用场景,一个软件系统可以提供多个外观不同的按钮(如圆形按钮、矩形按钮、菱形按钮等), 这些按钮都源自同一个基类,不过在继承基类后不同的子类修改了...
  • 抽象工厂 模式1. 简单工厂模式1.1 定义1.2 代码实现2. 工厂方法模式2.1 定义2.2 代码实现3. 抽象工厂模式3.1 定义3.2 代码实现 1. 简单工厂模式 1.1 定义 将apple、orange对象的new操作全部集成到1个工厂(Simple...
  • 实现四、抽象工厂模式1. 结构2. 实现五、工厂模式 + 反射 + 配置文件解除耦合六、JDK中使用工厂模式的类 一、前言 需要设计一个咖啡店点餐系统,需要创建的类有: 咖啡类(Coffee) 子类美式咖啡(AmericanCoffee...
  • 抽象工厂模式 相较于普通工厂模式,抽象工厂模式的规模更大,是围绕一个超级工厂创建其他的工厂,可以理解为生产工厂的工厂。 原理理解 自己的衣柜里挂着各种不同的衣服,我们可以将衣柜理解为工厂,从里面可以获得...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 209,560
精华内容 83,824
关键字:

工厂方法和抽象工厂