设计模式学习总结:(7)工厂方法模式和抽象工厂模式

工厂方法模式应该算是很容易理解的模式,至少从书上看是这样一回事,但是真正深入去理解它一种存在意义却是不容易的(代码量不够-。-)。从语法上看,无非就是把面向对象的多态特性封装到了内部工程类,实现运行时多态。

意图:

定义一个用于创建对象的接口,让子类决定实例化哪个类。Factory Method使一个类的实例化延迟到其子类。

结构图:

简单的代码:

class AbProduct
{
public:
    virtual void sayName()=0;
    AbProduct(string name) :_name(name){}
    virtual ~AbProduct(){}
protected:
    string _name;
};

具体产品:

class DBProduct:public AbProduct
{
public:
    DBProduct(string name) :AbProduct(name){}
    ~DBProduct(){}
    void sayName();
private:

};

void DBProduct::sayName()
{
    cout << _name << endl;
}
class TextProduct:public AbProduct
{
public:
    TextProduct(string name) :AbProduct(name){}
    ~TextProduct(){}
    void sayName();
private:

};
void TextProduct::sayName()
{
    cout << _name << endl;
}

抽象工厂:

class AbFactory
{
public:
    AbFactory(){}
    virtual ~AbFactory(){}
    virtual AbProduct * creator(string) = 0;
private:

};

具体工厂:

class DbFactory:public AbFactory
{
public:

    ~DbFactory(){}
    AbProduct * creator(string name);
private:

};
AbProduct * DbFactory::creator(string name)
{
    return new DBProduct(name);
}
class TextCreator :public AbFactory
{
public:

    ~TextCreator(){}
    AbProduct * creator(string name);
};
AbProduct * TextCreator::creator(string name)
{
    return new TextProduct(name);
}

测试:

int main()
{
        AbFactory *f = new DbFactory();
    AbProduct *d = f->creator("小db");

    d->sayName();
    delete f;
    delete d;

    return 0;
}

结果:

直接按照结构来比较抽象。

所以我又写了一些代码

class Client
{
public:
    Client(AbFactory * factory) :_factory(factory){}
    ~Client()
    {
        delete _factory;
    }
    void creatSon(string);

private:
    AbFactory *_factory;

};
void Client::creatSon(string name)
{
    AbProduct * son = _factory->creator(name);
    cout << "create a son" << endl;
    son->sayName();
    delete son;
}

我是在想,对于类似与creatSon这样的方法,需要在一个方法中动态的确定一个对象,而且这个对象应该不可以是唯一的。那么这个时候这种工厂模式的意义相当的凸显。

然后我还写了一点测试代码,之所以写这么无厘头,只是为了说明有这样一种时候,某个对象中每个执行过程需要动态new一个对象,而且每次调用这个执行过程都不应该是同一个对象,后面我写了一段同一个对象的情况。

先看测试代码:

int main()
{
    AbFactory *f = new DbFactory();
    Client dbClint = Client(f);
    dbClint.creatSon("小db");
    dbClint.creatSon("大db");
    Client textClint = Client(new TextFactory());
    textClint.creatSon("小text");
    return 0;
}

结果:

然后在看一个对比的代码:

class Client
{
public:
    Client(AbProduct * product) :_product(product){}
    ~Client()
    {
        delete _product;
    }
    void onlySonSayName();

private:
    AbProduct *_product;

};
void Client::onlySonSayName()
{

    _product->sayName();
}

这样也能实现多态,但是这个过程中不涉及到new,一个动态product已经够用了。

好了,接下来学了抽象工厂模式。相比普通工厂方法模式一个一个的new对象,抽象工厂更多的关注一堆对象之间的new,什么意思呢,在有些情况下,多个对象存在某种不可分割的关系,这个时候,用抽象工厂方法把所有的对象创建一次性组合成一个大工厂,这样显得更加的安全可靠(狂拽酷炫吊炸天)。当然,纸上谈兵还是很容易的,看看书上的一些定义吧。

意图:

提供一个创建一系列相关或相互依赖的对象的接口,而无需指定它们具体的类。

结构图:

具体的例子改写李建忠老师的例子吧,觉得挺有代表性的。比如数据库的操作封装,抽象成为最简单的步骤,就是connect,执行command,reader,最后在关闭,这一样的每一个步骤用一个类来表示,同时,数据库有很多种,为了便于后期扩展,所以都需要抽象出每一个类,因为每一次连接都需要new一个具体的对象,因为每一个连接是相互独立的,所以这个时候用工厂方法在合适不过了。

先看基本的代码:

抽象基类:

class DbConnection
{
public:
    virtual void connect(string)=0;
    DbConnection(){}
    virtual ~DbConnection(){} //虚析构函数其实是很有必要的
};
class Execute
{
public:
    Execute()=default;
    virtual ~Execute(){}
    virtual void execute(string sql_str)=0;
private:

};
class Reader
{
public:
    Reader()=defalut;
    virtual ~Reader(){}
    virtual void read()=0;
private:

};

如果需要扩展:

class MysqlConnect :public DbConnection
{
public:
    MysqlConnect(){}
    virtual ~MysqlConnect(){}
    void connect(string);
};
void MysqlConnect::connect(string conn_str)
{
    cout << "mysql连接中..." << endl;
    //实现代码
    cout << "连接成功" << endl;
}
class MysqlExecute:public Execute
{
public:
    MysqlExecute()=default;
    virtual ~MysqlExecute();
    void execute(string);
private:

};
void MysqlExecute::execute(string sql_str)
{
    cout << "执行mysql语句" << endl;
}
class MysqlReader:public Reader

{
public:
    MysqlReader()=default;
    virtual ~MysqlReader(){}
    void read();
private:

};

void MysqlReader::read()
{
    cout << "mysql数据已经取出" << endl;
}

orcle扩展:

class OlcleConnect :public DbConnection
{
public:
    OlcleConnect(){}
    virtual ~OlcleConnect(){}
    void connect(string);
};
void OlcleConnect::connect(string conn_str)
{
    cout << "Olcle连接中..." << endl;
    //实现代码
    cout << "连接成功" << endl;
}
class OlcleExecute :public Execute
{
public:
    OlcleExecute()=default;
    virtual ~OlcleExecute(){}
    void execute(string);
private:

};
void OlcleExecute::execute(string sql_str)
{
    cout << "执行Olcle语句" << endl;
}
class OlcleReader :public Reader

{
public:
    OlcleReader()=default;
    virtual ~OlcleReader(){}
    void read();
private:

};

void OlcleReader::read()
{
    cout << "Olcle数据已经取出" << endl;
}

最糟糕的实现莫过于此,如果上天给我一次机会,一定不会这么写:

class DbEmployee
{
public:
    void getEmployees()
    {
        MysqlConnect * mysql_conn = new MysqlConnect();
        mysql_conn->connect("210.11.11.11:8000->db");
        MysqlExecute *mysql_exe = new MysqlExecute();
        mysql_exe->execute("select * from student");
        MysqlReader *mysql_read = new MysqlReader();
        mysql_read->read();
        //记得删除对象
    }
    void Close()
    {
        //关闭中
    }

};

应该很容易看出来了,DbEmplee对象之中违背本末倒置原则,在变化中依赖具体的mysql对象,从而导致无法更好扩展orcle对象。

如果是最简单的工厂模式,那么我要写多几个工厂类:

一次性三个抽象工程:

class DbConnectionFactory
{
public:
    virtual DbConnection *createConnection() = 0;
    virtual ~DbConnectionFactory(){}
};

class DbExecuteFactory
{
public:
    virtual Execute *createExecute() = 0;
    virtual ~DbExecuteFactory(){}

private:

};

class DbReaderFactory
{
public:
    virtual Reader *createReader() = 0;
    virtual ~DbReaderFactory(){}

private:

};

扩展mysql工厂:

class MysqlConnectionFactory:public DbConnectionFactory
{
public:
    DbConnection *createConnection();
};
DbConnection * MysqlConnectionFactory::createConnection()
{
    return new MysqlConnect();
}

class MysqlExecuteFactory:public DbExecuteFactory
{
public:
    MysqlExecuteFactory()=default;
    ~MysqlExecuteFactory(){}
    Execute *createExecute();
private:

};
Execute *MysqlExecuteFactory::createExecute()
{
    return new MysqlExecute();
}

class MysqlReaderFactory :public DbReaderFactory
{
public:
    ~MysqlReaderFactory(){}
    Reader *createReader();
};
Reader * MysqlReaderFactory::createReader()
{
    return new MysqlReader();
}

orcle扩展:

class OrcleConnectionFactory :public DbConnectionFactory
{
public:
    DbConnection *createConnection();
};
DbConnection * OrcleConnectionFactory::createConnection()
{
    return new OrcleConnect();
}

class OrcleExecuteFactory :public DbExecuteFactory
{
public:
    OrcleExecuteFactory() = default;
    ~OrcleExecuteFactory(){}
    Execute *createExecute();
private:

};
Execute *OrcleExecuteFactory::createExecute()
{
    return new OrcleExecute();
}

class OrcleReaderFactory :public DbReaderFactory
{
public:
    ~OrcleReaderFactory(){}
    Reader *createReader();
};
Reader * OrcleReaderFactory::createReader()
{
    return new OrcleReader();
}

这个时候,就可以这么封装了。

class DbEmployee
{
public:
    DbEmployee(DbConnectionFactory *conn_f, DbExecuteFactory *Exe_f, DbReaderFactory *read_f)
        :_connFactory(conn_f), _executeFactory(Exe_f), _readerFactory(read_f){}
    ~DbEmployee()
    {
        delete _connFactory;
        delete _executeFactory;
        delete _readerFactory;
    }
    void getEmployees()
    {
        DbConnection * conn = _connFactory->createConnection();
        Execute * executer = _executeFactory->createExecute();
        Reader * reader = _readerFactory->createReader();
        conn->connect("210.11.11.11:3333->db");
        executer->execute("select * from student");
        reader->read();

    }
    void close()
    {
        //关闭中
    }
private:
    DbConnectionFactory * _connFactory;
    DbExecuteFactory * _executeFactory;
    DbReaderFactory * _readerFactory;

};

支持动态绑定:

int main
{
    DbEmployee good = DbEmployee(new MysqlConnectionFactory, new MysqlExecuteFactory, new MysqlReaderFactory);
    good.getEmployees();
    return 0;
}

运行结果:

到目前为止,我们还是在普通的工厂方法实现,所以上面的Dbemployee类还是有点问题的,比如如果不小心传入了不一致的Factory对象,将导致什么后果,三个Factory对象在实际过程中是有公有上下文,所以这三个factory对象最好还是要放在一起。同时这样写参数也是令人捉急。下面我把上面的工厂在改写一下:

首先改写抽象工厂,注意对比:

class BigFactory
{
public:
    virtual ~BigFactory(){}
    virtual DbConnection *createConnection() = 0;
    virtual Execute *createExecute() = 0;
    virtual Reader *createReader() = 0;

};

这是三个有关联的对象,实际过程中可能有数据交互。

扩展mysql大工厂:

class MysqlBigFactory :public BigFactory
{
public:
    DbConnection *createConnection();
    Execute *createExecute();
    Reader *createReader();
};
DbConnection *MysqlBigFactory::createConnection()
{
    return new MysqlConnect();
}
Execute *MysqlBigFactory::createExecute()
{
    return new MysqlExecute();
}
Reader *MysqlBigFactory::createReader()
{
    return new MysqlReader();
}

orcle:

class OrcleBigFactory :public BigFactory
{
public:
    DbConnection *createConnection();
    Execute *createExecute();
    Reader *createReader();
};
DbConnection *OrcleBigFactory::createConnection()
{
    return new OrcleConnect();
}
Execute *OrcleBigFactory::createExecute()
{
    return new OrcleExecute();
}
Reader *OrcleBigFactory::createReader()
{
    return new OrcleReader();
}

高度封装的DbEmployee对象:

class DbEmployee
{
public:
    DbEmployee(BigFactory *bigFactory)
        :_bigFactory(bigFactory){}
    ~DbEmployee()
    {
        delete _bigFactory;
    }
    void getEmployees()
    {
        DbConnection * conn = _bigFactory->createConnection();
        Execute * executer = _bigFactory->createExecute();
        Reader * reader = _bigFactory->createReader();
        conn->connect("210.11.11.11:3333->db");
        executer->execute("select * from student");
        reader->read();

    }
    void close()
    {
        //关闭中
    }
private:
    BigFactory * _bigFactory;

};

在使用的时候,就能看出好处了:

int main
{
    DbEmployee mysqlEmp = DbEmployee(new MysqlBigFactory);
    mysqlEmp.getEmployees();
    cout << "对比-----------------------" << endl;
    DbEmployee orcleEmp = DbEmployee(new OrcleBigFactory);
    orcleEmp.getEmployees();
    return 0;
}

使用很简单,只需要传入一个相应工厂对象,就可以在不同数据库之间无缝切换,互不干扰。

好了,一溜烟的全部写了这么多,应该有很多问题,但是大体思路就是这样。

时间: 2024-08-23 00:32:52

设计模式学习总结:(7)工厂方法模式和抽象工厂模式的相关文章

工厂模式:简单工厂模式、工厂方法模式和抽象工厂模式

我们一般制造对象时,采用操作符new来进行创建.但是慢慢我们了解到实例化这个活动不应该总是公开地进行,同时初始化还经常造成"耦合"的问题. 如果我们不希望出现上述问题,那么我们就有必要认识一下"工厂模式",它将有助于我们从复杂的依赖中解脱出来. 1)为什么说"new"不好? 当看到"new",就会想到"具体". 我们不应该总是针对实现编程,但是当我们每次使用new时,正是在针对实现编程而不是接口,这很不符合

简单工厂模式、工厂方法模式和抽象工厂模式-设计模式学习

1.简单工厂模式 简单工厂模式是属于创建型模式,又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一.简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例.简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现. 工厂(Creator)角色 简单工厂模式的核心,它负责实现创建所有实例的内部逻辑.工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象. 抽象产品(Product)角色 简单工厂模式所创建的所有

iOS设计模式——工厂方法(简单工厂模式,工厂方法模式, 抽象工厂模式)

1. 简单工厂模式 如何理解简单工厂,工厂方法, 抽象工厂三种设计模式? 简单工厂的生活场景,卖早点的小摊贩,他给你提供包子,馒头,地沟油烙的煎饼等,小贩是一个工厂,它生产包子,馒头,地沟油烙的煎饼.该场景对应的UML图如下所示: 图1:简单工厂模式UML图 简单工厂模式的参与者: 工厂(Factory)角色:接受客户端的请求,通过请求负责创建相应的产品对象. 抽象产品(Abstract Product)角色: 是工厂模式所创建对象的父类或是共同拥有的接口.可是抽象类或接口. 具体产品(Conc

设计模式系列——三个工厂模式(简单工厂模式,工厂方法模式,抽象工厂模式)

原文地址:http://blog.chinaunix.net/uid-25958655-id-4243289.html 简单工厂模式 当需要加法类的时候,调用工厂类的CreateOperate(),要指定制造的Product 例如在大话设计模式P11给的运算工厂例子: public static Operation createOperate(string operate) { Operation oper = null; 12 switch (operate) { case "+":

iOS常用设计模式——工厂方法(简单工厂模式,工厂方法模式, 抽象工厂模式)

1. 简单工厂模式 如何理解简单工厂,工厂方法, 抽象工厂三种设计模式? 简单工厂方法包含:父类拥有共同基础接口,具体子类实现子类特殊功能,工厂类根据参数区分创建不同子类实例.该场景对应的UML图如下所示: 代码结构如下 Animal 类 @interface Animal :NSObject @proterty(nonatomic,strong) NSString *name; -(void)laugh; @end Dog类 @interface Dog:Animal @end Cat类 @i

iOS经常使用设计模式——工厂方法(简单工厂模式,工厂方法模式, 抽象工厂模式)

1. 简单工厂模式 怎样理解简单工厂,工厂方法. 抽象工厂三种设计模式? 简单工厂的生活场景.卖早点的小摊贩.他给你提供包子,馒头,地沟油烙的煎饼等,小贩是一个工厂.它生产包子,馒头,地沟油烙的煎饼. 该场景相应的UML图例如以下所看到的: 图1:简单工厂模式UML图 简单工厂模式的參与者: 工厂(Factory)角色:接受client的请求,通过请求负责创建对应的产品对象. 抽象产品(Abstract Product)角色:是工厂模式所创建对象的父类或是共有的接口.但是抽象类或接口. 详细产品

设计模式之_简单工厂模式、工厂方法模式、抽象工厂模式 、策略模式、策略与工厂的区别(转)

一.前言 话说十年前,有一个爆发户,他家有三辆汽车(Benz(奔驰).Bmw(宝马).Audi(奥迪)),还雇了司机为他开车.不过,爆发户坐车时总是这样:上Benz车后跟司机说“开奔驰车!”,坐上Bmw后他说“开宝马车!”,坐上 Audi后他说“开奥迪车!”.你一定说:这人有病!直接说开车不就行了?!而当把这个爆发户的行为放到我们程序语言中来,我们发现C语言一直是通过这种方式来坐车的 幸运的是这种有病的现象在OO语言中可以避免了.下面以Java语言为基础来引入我们本文的主题:工厂模式! 二.简介

Java设计模式-工厂方法模式和抽象工厂模式

工厂方法模式定义: 即定义一个创建对象的接口(即抽象工厂类),让其子类(具体工厂类)决定实例化哪一个类(具体产品类)."一对一"的关系 1,一抽象工厂类派生出多个具体工厂类: 2,一抽象产品类派生出多个具体产品类: 3,每个具体工厂类只能创建一个具体产品类的实例. UML图: 角色模块: 1,抽象工厂类:工厂方法模式的核心,定义一个创建对象的接口 2,具体工厂类:继承抽象工厂类,实现其工厂方法,实现具体业务逻辑 3,抽象产品类:是工厂方法模式所创建的产品的父类 4,具体产品类:实现抽象

&quot;围观&quot;设计模式(8)--创建型之简单工厂模式、工厂方法模式、抽象工厂模式

工厂模式的核心思想在我认为是将类创建的权利授予给工厂类,其他的类不允许创建,授予了权限的类创建好之后,需要某些的对象的时候,可以去工厂当中去取.也就是像一个工厂一样,用的人不需要关心对象怎么来的,你只需要关心怎么用就好了.工厂模式细分为三种,简单工厂.工厂方法.抽象工厂三种模式.这三种模式比较相似,往往会引发混淆,本文主要结合实际的例子去进行区分.理清三者之间的关系与适用范围. 概述 简单工厂 对于简单工厂,我个人的理解是,直接实现一个方法,要生产什么由这个方法以及传入的参数来决定. 工厂方法

java设计模式 -------- 创建模式 之 抽象工厂模式

本文是自己学习所做笔记,欢迎转载,但请注明出处:http://blog.csdn.net/jesson20121020 工厂方法模式和抽象工厂模式不好区分清楚: 工厂方法模式特点: 1. 一个抽象产品类,可以派生出多个具体产品类. 2. 一个抽象工厂类,可以派生出多个具体工厂类. 3. 每个具体工厂类只能创建一个具体产品类的实例. 抽象工厂模式特点: 1. 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类. 2. 一个抽象工厂类,可以派生出多个具体工厂类. 3. 每个具体工厂类可以创建多个