一万光年外  
免费OA软件网 http://www.freeoasoft.com 专注于平台架构设计及OA软件开发
(因家里没有装建模工具,而VS2005的类图老是用不惯,需等以后有时间再补上类图)

有这样一个场景,假设我是一家电器生产公司职员,主要工作是从设计部那里拿到设计好的图纸,然后交给生产部门进行生产,再对生产好的产品进行相关的检测.需要做一套系统来显示测试的结果.

刚开始公司只生产一种型号的冰箱,需要检测的是冰箱的冷冻能力.那我们可能会这样实现:
    public class IceBox
    {
        
public double FreezePower() //冷冻能力
        {
        
return 1;
        }
    }

    
public class Factory
    {
        
public IceBox CreateIceBox()
        {
        
return new IceBox();
        }
    }

    
public class My
    {
        
private void ShowInfo()
        {
            IceBox icebox 
= new Factory().CreateIceBox();
        MessageBox.Show(icebox.FreezePower().ToString()); 
//显示1
        }        
    }

看起来很不错,也很简单!不过没多久问题就来了,现在公司又生产了另外一种型号的冰箱,要对两种型号的冰箱进行检测,我们应该怎么做,难道是像下面一样:
    public class IceBoxA //A型冰箱
    {
        
public double FreezePower() //冷冻能力
        {
        
return 1;
        }
    }

    
public class IceBoxB //B型冰箱
    {
        
public double FreezePower() //冷冻能力
        {
        
return 2;
        }
    }

    
public class Factory
    {
        
public IceBoxA CreateIceBoxA()
        {
        
return new IceBoxA();
        }

        
public IceBoxB CreateIceBoxB()
        {
        
return new IceBoxB();
        }
    }

    
public class My
    {
        
private void ShowInfo()
        {
        
if (测试的是A型冰箱)
        {
                IceBoxA iceboxa 
= new Factory().CreateIceBoxA();
            MessageBox.Show(iceboxa.FreezePower().ToString()); 
//显示1
        }
        
else
        {
                IceBoxB iceboxb 
= new Factory().CreateIceBoxB();
            MessageBox.Show(iceboxb.FreezePower().ToString()); 
//显示2
        }
        }        
    }

看到这里,性子急的人可能会骂起来了,这当然不行,如果我们以后又增加了C,D,E,F..型号,那怎么办?
的确,我们可以做得更好!有经验的高手一般就会这样做:
    public interface IIceBox   //增加冰箱的通用接口
    {
        
double FreezePower();  //冷冻能力
    }

    
public class IceBoxA : IIceBox //A型冰箱
    {
        
public double FreezePower() //冷冻能力
        {
        
return 1;
        }
    }

    
public class IceBoxB : IIceBox //B型冰箱
    {
        
public double FreezePower() //冷冻能力
        {
        
return 2;
        }
    }

    
public class Factory
    {
        
public IIceBox CreateIceBox(string Mode)
        {
        
if (Mode == "A"return new IceBoxA();
        
else return new IceBoxB();
        }
    }

    
public class My
    {
        
private void ShowInfo()
        {
        Factory factory 
= new Factory();
        IIceBox icebox 
= factory.CreateIceBox("A");
        
        MessageBox.Show(icebox.FreezePower().ToString()); 
//显示1,如上一步换为"B",则显示2
        }        
    }
这比刚才的要好多了吧!My不用知道具体冰箱的型号,如果再增加C型冰箱,扩充也更容易!其实这就叫简单工厂模式!

不过随着公司规模的扩大,又新建了一个工厂,A工厂只生产A型冰箱,B工厂只生产B型冰箱,问题又出来了,总不可
能直接增加一个FactoryB吧,那以后又增加几个工厂呢?
与上面的思想类似,其实我们可以这样做:
    public interface IFactory   //增加工厂的通用接口
    {
        IIceBox CreateIceBox();  
//生产冰箱
    }

    
public class FactoryA : IFactory   //A型工厂
    {
        
public IIceBox CreateIceBox() //生产A型冰箱
        {
        
return new IceBoxA();
        }
    }

    
public class FactoryB : IFactory  //B型工厂
    {
        
public IIceBox CreateIceBox() //生产B型冰箱
        {
        
return new IceBoxB();
        }
    }

    
public class My
    {
        
private IFactory GetFactory(string Mode)
        {
        
if (Mode == "A"return new FactoryA();
        
else return new FactoryB();
        }

        
private void ShowInfo()
        {
        IFactory factory 
= GetFactory("A");
        IIceBox icebox 
= factory.CreateIceBox();
        MessageBox.Show(icebox.FreezePower().ToString()); 
//显示1,如上上一步换为"B",则显示2
        }        
    }
这比直接增加FactoryB要好多了,具体的调用方法不用改变,也不需要知道冰箱的类型!即使再增加工厂C,改动也不大!这就是工厂模式!

不过随着公司规模进一步扩大,出现了这样的需求:
1. 公司不仅要生产冰箱,还要生产冼衣机.
2. 冰箱和洗衣机都分A型和B型.
3. A型工厂生产A型冰箱和洗衣机(投放国内市场),B型工厂生产B型冰箱和洗衣机(出口)

当然我们可以继续在上面的方案上进行扩充:
    public interface IWasher   //增加洗衣机通用接口
    {
        
double WashPower;  //洗涤效果
    }

    
public class WasherA : IWasher //实现A型冰箱
    {
        
public double WashPower() //洗涤效果
        {
        
return 1;
        }
    }

    
public class WasherB : IWasher //实现B型冰箱
    {
        
public double WashPower() //洗涤效果
        {
        
return 2;
        }
    }

    
public interface IFactory   //扩充工厂的通用接口
    {
        IIceBox CreateIceBox();  
//生产冰箱
        IWasher CreateWasher();  //生产洗衣机
    }

    
public class FactoryA : IFactory   //扩充A型工厂
    {
        
public IIceBox CreateIceBox() //生产A型冰箱
        {
        
return new IceBoxA();
        }

        
public IWasher CreateWasher() //生产A型洗衣机
        {
        
return new IceBoxA();
        }
    }

    
public class FactoryB : IFactory  //扩充B型工厂
    {
        
public IIceBox CreateIceBox() //生产B型冰箱
        {
        
return new IceBoxB();
        }

        
public IWasher CreateWasher() //生产B型洗衣机
        {
        
return new WasherB();
        }
    }

    
public class My
    {
        
private IFactory factory = null//注意:保存全局工厂实例,以便减少下次调用的实例化

        
private void GetFactory(string Mode)
        {
        if (Mode == "A") factory = new FactoryA();
        
else factory = new FactoryB();
        }

        
private void ShowInfo()
        {
        GetFactory(
"A");
        IIceBox icebox 
= factory.CreateIceBox();
        MessageBox.Show(icebox.FreezePower().ToString()); 
//显示1,如上上一步换为"B",则显示2

        IWasher washer 
= factory.CreateWasher();
        MessageBox.Show(washer.WashPower().ToString()); 
//洗涤能力:显示1,如前面换为"B",则显示2
        }        
    }
这就是抽象工厂模式!
在.NET 2.0有一个抽象工厂模式的典型应用:通过DBProviderFactory 建立不同数据库类型的操作!
其基本对应关系如下:
1. DBProviderFactory 对应前面的 IFactory, 而具体的如SQLServer,Ocracle的DBProviderFactory对应前面

的FactoryA,FactoryB.
2. DBConnetion 对应 IIceBox, 而SQLConnetion,OracleConnection对应前面的IceBoxA,WasherA.
3. DBCommand 对应 IWasher,而SQLCommand,OracleCommand对应前面的IceBoxB,WasherB

具体类图以后一并补上!


不好意思,前一段没有完全说清楚工厂模式的具体用途,现补充如下:

总结:工厂模式的好处其实在于统一不同产品的访问接口!比如说我们在写数据库应用程序时,如果为SQL Server,则用SQLConnection,如为Oracle,则用OracleConnection.
一般在程序中写:SQLConnection conn = new SQLConnection(); 那如果要改为Oracle,则要重新改写并重编代码,但如果用工厂模式,则可以这样做:
DBProviderFactory factory = DBProviderFactorys.GetFactory("System.Data.SqlClient"); //可通过配置改变
DBConnection conn = factory.CreateConnection();
conn.ConnectionString = .....
也就达到了不用改动代码即实现更换不同数据库的目的!

posted on 2006-08-11 23:08  一万光年外  阅读(2055)  评论(10编辑  收藏  举报
 
免费OA软件网 http://www.freeoasoft.com 专注于平台架构设计及OA软件开发