工厂方法模式应该算是很容易理解的模式,至少从书上看是这样一回事,但是真正深入去理解它一种存在意义却是不容易的(代码量不够-。-)。从语法上看,无非就是把面向对象的多态特性封装到了内部工程类,实现运行时多态。
意图:
定义一个用于创建对象的接口,让子类决定实例化哪个类。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; }
使用很简单,只需要传入一个相应工厂对象,就可以在不同数据库之间无缝切换,互不干扰。
好了,一溜烟的全部写了这么多,应该有很多问题,但是大体思路就是这样。