随笔-91  评论-137  文章-0  trackbacks-0

抽象工厂模式

前序

“这么晚才回来,都11点了。”大鸟看着刚推门而入的小菜问道。

“嗨,没办法呀,工作忙。”小菜叹气说道。

“怎么会这么忙,加班有点过头了呀。”

“都是换数据库惹的祸呗。”

“怎么了?”

“我本来写好了一个项目,是给一家企业做的电子商务网站,是用SQL Server作为数据库的,应该说上限后除了开始有些小问题,基本都还可以。而后,公司截到另外一家公司类似需求的项目,但这家公司想省钱,租用了一个空间,只能用Access,不能用SQL Server,于是就要求我今天改造原来那个项目的代码。”

“哈哈,你的麻烦来了。”

“是呀,那是相当的麻烦。但开始我觉得很简单呀,因为地球人都知道,SQL ServerAccessADO.NET上的使用是不同的。我以为只要做一个全体替换就可以了,哪知道,替换后,错误百出。”

“以后你还有的是班要加了。”

“为什么?”

“只要网站要维护,比如修改或增加一些功能,你就得改两个项目吧,至少在数据库中做改动,响应的程序代码都要改,甚至和数据库不想干的代码也要改,你既然有两个不同的版本,两倍的工作量也是必然的。”

“是呀,如果哪天要用Oracle数据库,估计我要改动的地方更多了。”

“那是当然,OracleSQL语法与SQL Server的差别更大。你的改动将是空前的。”

最基本的数据访问程序

“你先写一段你原来的数据库访问的做法给我看看。”

“那就用‘新增用户’和‘得到用户’为例吧。”

#include <stdio.h>

 

class User

{

public:

       int id;

       char* name;

};

 

class SqlserverUser

{

public:

       void Insert(User* user)

       {

              printf("SQL Server中给User表添加一条记录\n");

       }

 

       User* GetUser(int id)

       {

              printf("SQL Server中根据ID得到User表一条记录\n");

              return 0;

       }

};

 

int main()

{

       User* user = new User();

       SqlserverUser* su = new SqlserverUser();

       su->Insert(user);

       su->GetUser(1);

       delete user;

       delete su;

       return 0;

}

“我最开始就是这样写的,非常简单。”

“这里之所以不能换数据库,原因就在于SqlserverUser* su = new SqlserverUser();使得su这个对象被框死在SQL Server上了。如果这里是灵活的,专业点的说法,是多态的,那么在执行‘su->Insert(user);’和‘su->GetUser(1);’时就不用考虑是在用SQL Server还是在用Access了。”

用工厂方法模式的数据访问程序

#include <stdio.h>

 

class User

{

public:

       int id;

       char* name;

};

 

class IUser

{

public:

       virtual void Insert(User* user)=0;

       virtual User* GetUser(int id)=0;

};

 

class SqlserverUser : public IUser

{

public:

       virtual void Insert(User* user)

       {

              printf("SQL Server中给User表添加一条记录\n");

       }

 

       virtual User* GetUser(int id)

       {

              printf("SQL Server中根据ID得到User表一条记录\n");

              return 0;

       }

};

 

class AccessUser : public IUser

{

public:

       virtual void Insert(User* user)

       {

              printf("Access中给User表添加一条记录\n");

       }

 

       virtual User* GetUser(int id)

       {

              printf("Access中根据ID得到User表一条记录\n");

              return 0;

       }

};

 

class IFactory

{

public:

       virtual IUser* CreateUser()=0;

};

 

class SqlServerFactory : public IFactory

{

public:

       virtual IUser* CreateUser()

       {

              return new SqlserverUser();

       }

};

 

class AccessFactory : public IFactory

{

public:

       virtual IUser* CreateUser()

       {

              return new AccessUser();

       }

};

 

int main()

{

       User* user = new User();

       IFactory* factory = new SqlServerFactory();

       IUser* iu = factory->CreateUser();

       iu->Insert(user);

       iu->GetUser(1);

       delete user;

       delete factory;

       delete iu;

       return 0;

}

“非常好。现在如果要换数据库,只需要把new SqlServerFactory()改成new AccessFactory(),此时由于多态的关系,使得声明IUser接口的对象iu实现根本不知道是在访问哪个数据库,却可以在运行时很好的完成工作,这就是所谓的业务逻辑与数据访问的解耦。”

“但是,大鸟,这样写,代码里还是有指明‘new SqlServerFactory()’呀,我要改的地方,依然很多。”

“这个先不急,待会再说,问题没有完全解决,你的数据库里不可能只有一个User表吧,很可能有其他表,比如增加部门表(Department),此时如何办呢?”

抽象工厂模式

客户类和工厂类分开。消费者任何时候需要某套产品集合时,只需向抽象工厂请求即可。抽象工厂会再向具体的工厂生产出符合产品集规格的产品。

实现方式(UML类图)


实现代码

#include <stdio.h>

 

class User

{

public:

       int id;

       char* name;

};

 

class Department

{

public:

       int id;

       char* deptname;

};

 

// User表接口

class IUser

{

public:

       virtual void Insert(User* user)=0;

       virtual User* GetUser(int id)=0;

};

 

// Department表接口

class IDepartment

{

public:

       virtual void Insert(Department* department)=0;

       virtual Department* GetDepartment(int id)=0;

};

 

class SqlserverUser : public IUser

{

public:

       virtual void Insert(User* user)

       {

              printf("SQL Server中给User表添加一条记录\n");

       }

 

       virtual User* GetUser(int id)

       {

              printf("SQL Server中根据ID得到User表一条记录\n");

              return 0;

       }

};

 

class AccessUser : public IUser

{

public:

       virtual void Insert(User* user)

       {

              printf("Access中给User表添加一条记录\n");

       }

 

       virtual User* GetUser(int id)

       {

              printf("Access中根据ID得到User表一条记录\n");

              return 0;

       }

};

 

class SqlserverDepartment : public IDepartment

{

public:

       virtual void Insert(Department* department)

       {

              printf("SQL Server中给Department表增加一条记录\n");

       }

      

       virtual Department* GetDepartment(int id)

       {

              printf("SQL Server中根据ID得到Department表一条记录\n");

              return 0;

       }

};

 

class AccessDepartment : public IDepartment

{

public:

       virtual void Insert(Department* department)

       {

              printf("Access中给Department表增加一条记录\n");

       }

      

       virtual Department* GetDepartment(int id)

       {

              printf("Access中根据ID得到Department表一条记录\n");

              return 0;

       }

};

 

// IFactory接口

class IFactory

{

public:

       virtual IUser* CreateUser()=0;

       virtual IDepartment* CreateDepartment()=0;

};

 

class SqlServerFactory : public IFactory

{

public:

       virtual IUser* CreateUser()

       {

              return new SqlserverUser();

       }

      

       virtual IDepartment* CreateDepartment()

       {

              return new SqlserverDepartment();

       }

};

 

class AccessFactory : public IFactory

{

public:

       virtual IUser* CreateUser()

       {

              return new AccessUser();

       }

      

       virtual IDepartment* CreateDepartment()

       {

              return new AccessDepartment();

       }

};

 

int main()

{

       User* user = new User();

       Department* dept = new Department();

      

       IFactory* factory = new AccessFactory();

      

       IUser* iu = factory->CreateUser();

       iu->Insert(user);

       iu->GetUser(1);

      

       IDepartment* id = factory->CreateDepartment();

       id->Insert(dept);

       id->GetDepartment(1);

      

       delete user;

       delete dept;

       delete factory;

       delete iu;

       delete id;

       return 0;

}

运行结果



所有文件打包下载

posted on 2011-06-26 22:19 lwch 阅读(3324) 评论(2)  编辑 收藏 引用 所属分类: 设计模式

评论:
# re: 抽象工厂模式 2012-11-06 17:14 | 。。。
没有反射啊,后面的反射没有讲  回复  更多评论
  
# re: 抽象工厂模式 2012-11-07 14:05 | lwch
@。。。
C++有办法实现反射吗?  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理