Chinaunix首页 | 论坛 | 博客
  • 博客访问: 570232
  • 博文数量: 155
  • 博客积分: 4015
  • 博客等级: 上校
  • 技术积分: 1625
  • 用 户 组: 普通用户
  • 注册时间: 2005-11-18 16:55
文章分类

全部博文(155)

文章存档

2009年(20)

2008年(39)

2007年(66)

2006年(29)

2005年(1)

我的朋友

分类: 项目管理

2007-09-17 14:17:39

 《设计模式》的书已买过有段时间了,看来看去像是看经书:都是实话,但似乎都是些没有用了。佛家讲这叫悟性不够。周五晚上看《Effictive C++》时突然来了些灵感,是顿悟嘛,我想不是。而是渐悟后的觉悟罢了。即然是好东西,分享当然是最快乐的事情了,那我现在就开始我的快乐之旅。
   Abstract Factory(抽象工厂),让我们先抛开程序设计的观感(虽然话是如此,我想这对像我一样的程序员来说很难,毕竟程序员都很执着),来看看抽象工厂是什么意思。工厂:用来生产东西的。抽象的工厂,哟哟哟...看来该工厂还是个假的并不实际存在。
   或许我们可以把抽象工厂当做呼唤“阿拉丁”神灯的那个怪物的咒语。你在念完咒语之后大叫:“我要个锤子。”没有多久一个锤子就会出现在你面前。你还可以在念完咒语之后大喊:“我要一台电脑。”那么没有多久一台崭新的电脑也会出现在你的面前。如果我要是掌握了这个咒语我会做什么呢?嗯,想到了。我会对着天空大叫三声:“给我一个女朋友吧!”。西西...
    书回原位,其实我们谁都都要这样一个工厂。毕竟想要什么都可以让工厂给我生产。在程序设计中出现这种情况会更多。让我们从一个实例开始吧(摘自《设计模式精解》):
    现在我们需要做一个系统软件需要支持不同的显示及打印分辨率。我们可能先会想以这个实现:
......
if 当前显示率为800*600 then
   new 打印驱动对象
打印驱动对象.打印
.....
if 当前显示率为800*600 then
   new 显示驱动对象
显示驱动对象.显示
 
如果我们需要new十个相应的驱动对象,红色部分是不是太麻烦(需要重复十次),万一你哪次写错了怎么办!你每次new对象时必须记住当前的分辨率,这是多么复杂和无聊的事情啊。
   Software's primary technical imperative: managing complexity(软件首要技术使命:管理复杂度)
                                           --McConnel(The author of code complete2)
既然这么复杂,那么我们该去管管它了。我们建立一个类来管管他。嗯...走到这步我们离Abstract Factory就不远啦.
   我们试想的方式是如下的:
......
给我一个打印驱动对象吧,这时一个打印驱动对象出现在你的面前
   打印驱动对象.打印
给我一个显示驱动对象吧,这时一个显示驱动对象出在在你的面前
   显示驱动对象.显示
......
   Oh.so nice...想要时就大呼一声,这是件多么令人向往的事啊."我要一个女朋友啊...小崔..这段掐了别播".
----------------------------
   再看看具体是怎么实现的,现给出完整代码(源码之前,了无秘密).在给出源码之前给出类图,以帮助理解.从下面这张图中可以看出[主程序]只和DrvFactory,Display,PrintDriver进行交互.再者这三个类(黄色)也都只是个接口(C++没有接口的概念,用Abstract class来实现).只和接口交互,隐藏了细节。这才是Abstract Factory本身想表达的意义。
Platform: WinXp+VC++6.0

/*----------------
No.: one
Filename: AbstractFactory.cpp
Desc: 主程序
----------------*/
#include
#include
#include "Factory.h"
using namespace Factory;


void main()
{
 DrvFactory *pResFactory;
 
 cout<<"Please input resolution,format likes \"800*600\" or \"1024*768\""< string strConfig("800*600");
 cin>>strConfig;
 
 if(strConfig == "800*600")
  pResFactory = new LowResolutionFactory();
 else if(strConfig == "1024*768")
  pResFactory = new HighResolutionFactory();
 else
 {
  cout<<"The format of resolution is error!"<  return;
 }


 //使用相应分辨率的驱动
 //这时你可以忘记具体的分辨率了(被封装起来了),需要用到Driver时至pResFactory"拿来"即可(拿来主义)
 DisplayDriver *pDisplayDriver = pResFactory->GetDispDrv();
 pDisplayDriver->Display();
 delete pDisplayDriver;  //用完将其删除,防止memory leak
 
 PrintDriver *pPrintDriver = pResFactory->GetPrintDrv();
 pPrintDriver->Print();
 delete pPrintDriver;

}


/*------------------------------------------------------
No.: two
Filename: DvrFactory.h
Desc: DrvFactory,LowResolutionFactory,HighResolutionFactory三个类的头文件
-------------------------------------------------------*/
#include "Headers.h"
using namespace Driver;

namespace Factory
{
 class DrvFactory
 {
 public:
  virtual ~DrvFactory(){};
  virtual DisplayDriver *GetDispDrv()=0;
  virtual PrintDriver *GetPrintDrv()=0;
 };
 
 class LowResolutionFactory:public DrvFactory
 {
 public:
  DisplayDriver *GetDispDrv();
  PrintDriver *GetPrintDrv();
 };
 class HighResolutionFactory:public DrvFactory
 {
 public:
  DisplayDriver *GetDispDrv();
  PrintDriver *GetPrintDrv();
 };
}


/*--------------------------
No.: three
Filename: DrvFactory.cpp
Desc: DrvFactory(抽象类,无实现文件),
      LowResolutionFactory,HighResolutionFactory二个类的实现文件
---------------------------*/

#include "Factory.h"
#include "headers.h"

using namespace Factory;
using namespace Driver;

//生成低分辨率Driver对象
DisplayDriver* LowResolutionFactory::GetDispDrv()
{
 return new LowResolutionDisplayDriver();
}
PrintDriver* LowResolutionFactory::GetPrintDrv()
{
 return new LowResolutionPrintDriver();
}

//生成高分辨率Driver对象
DisplayDriver* HighResolutionFactory::GetDispDrv()
{
 return new HighResolutionDisplayDriver();
}
PrintDriver* HighResolutionFactory::GetPrintDrv()
{
 return new HighResolutionPrintDriver();
}


/*--------------------------------------
No.: four
Filename: DisplayDriver.h
Desc: DisplayDriver,
      LowResolutionDisplayDriver,HighResolutionDisplayDriver三个(显示)类头文件
----------------------------------------*/

#include
using namespace std;
namespace Driver
{
 class DisplayDriver
 {
 public:
  virtual ~DisplayDriver(){};
  virtual void Display()=0;
 };

 class LowResolutionDisplayDriver:public DisplayDriver
 {
 public:
  void Display();
 };
 class HighResolutionDisplayDriver:public DisplayDriver
 {
 public:
  void Display();
 };
}


/*--------------------
No.: five
Filename: DisplayDriver.cpp
Desc: DisplayDriver(抽象类)
      LowResolutionDisplayDriver,HighResolutionDisplayDriver二个(显示)类的实现文件
---------------------*/
#include "DisplayDriver.h"
using namespace Driver;

void LowResolutionDisplayDriver::Display()
{
 cout<<"Display picture in Low Resolution(800*600)"<}
void HighResolutionDisplayDriver::Display()
{
 cout<<"Display picture in High Resolution(1024*768)"<}


/*------------
No.: six
Filename: PrintDriver.h
Desc: PrintDriver,
      LowResolutionPrintDriver,HighResolutionPrintDriver三个(打印)类的头文件
------------*/
#include
using namespace std;
namespace Driver
{
 class PrintDriver
 {
 public:
  virtual ~PrintDriver(){};
  virtual void Print()=0;
 };

 class LowResolutionPrintDriver: public PrintDriver
 {
 public:
  void Print();
 };
 class HighResolutionPrintDriver: public PrintDriver
 {
 public:
  void Print();
 };
}


/*-------------------------------
No.: seven
Filename: PrintDriver.cpp
Desc: PrintDriver(抽象类)
      LowResolutionPrintDriver,HighResolutionPrintDriver二个(打印)类实现文件
--------------------------------*/

#include "PrintDriver.h"
using namespace Driver;

void LowResolutionPrintDriver::Print()
{
 cout<<"Print the Photo in Low Resolution Printer..."<}

void HighResolutionPrintDriver::Print()
{
 cout<<"Print the Photo in High Resolution Printer..."<}


/*-----------------------------------
No.: eight
Filename:headers.h
Desc: 为了防止重复包含而定义的头文件
------------------------------------*/

#ifndef PRINTDRIVER_H
#define PRINTDRIVER_H
#include "PrintDriver.h"
#endif

#ifndef DISPLAYDRIVER_H
#define DISPLAYDRIVER_H
#include "DisplayDriver.h"
#endif


其实从最初的那张图来看,DrvFactory就是我们的呼唤"阿拉丁"神灯的咒语.我们管需要什么样的类,向其大喊一声即可.这最终还是一种封装的思想.Abstract Factory封装了一个创建具体对象的过程,这给我们程序设计带来的更大的灵活性和弹性.
 
  试想如果我们现在又增加了一个分析率1600*1200,那么我们要做哪些工作呢?
新增一个1600*1200的显示类(Derived from DisplayDriver)及打印类(Derived from PrintDriver)即可(这一步是必不可少的,所以我们只有乖乖地做好他)
  试想如果我们现在加了一个扫描仪那么我们又需做哪些工作呢?
我们只需新增一个扫描仪驱动类(ScannerDriver)即可.
看起来应该是下面这样(为了看起来清爽,我省略了部分虚线):
 
 
 
根本问题是这些更改并不会影响现存的代码,这是多么奇妙的事啊.
 
 
附记:昨天晚上写完之后,回去想了一下,觉得并没有表达清楚。自己想着都模糊怎么能让别人看的懂呢。既然语言表达不清楚,就用图吧。所以今天特地将两幅图更新了一下。希望可以见图知意。
 
 
 
 
 
 
 
 
 
Jerry.Chow
      9/17'07
阅读(1005) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~