惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Help Net Security
Help Net Security
宝玉的分享
宝玉的分享
Microsoft Security Blog
Microsoft Security Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
A
About on SuperTechFans
Microsoft Azure Blog
Microsoft Azure Blog
月光博客
月光博客
量子位
博客园 - 叶小钗
Last Week in AI
Last Week in AI
阮一峰的网络日志
阮一峰的网络日志
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
V2EX
D
DataBreaches.Net
Vercel News
Vercel News
博客园 - Franky
Recorded Future
Recorded Future
B
Blog RSS Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
GbyAI
GbyAI
M
MIT News - Artificial intelligence
F
Full Disclosure
S
SegmentFault 最新的问题
L
LangChain Blog
F
Fortinet All Blogs
美团技术团队
IT之家
IT之家
博客园 - 司徒正美
Cyberwarzone
Cyberwarzone
NISL@THU
NISL@THU
P
Privacy International News Feed
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Y
Y Combinator Blog
C
Check Point Blog
The GitHub Blog
The GitHub Blog
L
Lohrmann on Cybersecurity
I
Intezer
I
InfoQ
Spread Privacy
Spread Privacy
Project Zero
Project Zero
T
Threatpost
S
Secure Thoughts
C
Comments on: Blog
N
News | PayPal Newsroom
Application and Cybersecurity Blog
Application and Cybersecurity Blog
H
Heimdal Security Blog
T
The Blog of Author Tim Ferriss
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Hugging Face - Blog
Hugging Face - Blog
U
Unit 42

博客园 - 一万光年外

戏说平台 第七章 可插拔主控台 心情极度不爽,发几句牢骚,恳请放首页一天 戏说平台 第六章 煮酒论编程 戏说平台 异构外篇 与朋友的QQ聊天记录 戏说平台 第五章 异构 一种独特的实现异构数据库操作的方法 戏说平台 第四章 淫贱二人组 戏说平台 第三章 学艺 CDMP平台简介 PPT格式 戏说平台 第二章 拜师 戏说平台 第一章 穿越 可配置B/S,C/S两用平台之三:自定义业务续 可配置B/S,C/S两用平台之二:自定义业务 可配置B/S,C/S两用平台之一:系统概览 Ado.net处理数据库异常 Byte[]转十六进制 Action设计模式的.Net实现 安装SQL SERVER2000时出现程序挂起错误的解决方法 转载fyireporting Reporting Services主从表实现
老生常谈,设计模式之我见 - 工厂模式篇
一万光年外 · 2006-08-11 · via 博客园 - 一万光年外

(因家里没有装建模工具,而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 = .....
也就达到了不用改动代码即实现更换不同数据库的目的!