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

推荐订阅源

Latest news
Latest news
C
Check Point Blog
H
Help Net Security
Engineering at Meta
Engineering at Meta
Y
Y Combinator Blog
Stack Overflow Blog
Stack Overflow Blog
MyScale Blog
MyScale Blog
P
Proofpoint News Feed
Recorded Future
Recorded Future
Blog — PlanetScale
Blog — PlanetScale
T
The Blog of Author Tim Ferriss
H
Heimdal Security Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog RSS Feed
W
WeLiveSecurity
G
Google Developers Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
P
Proofpoint News Feed
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Martin Fowler
Martin Fowler
酷 壳 – CoolShell
酷 壳 – CoolShell
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
宝玉的分享
宝玉的分享
Apple Machine Learning Research
Apple Machine Learning Research
The GitHub Blog
The GitHub Blog
C
CERT Recently Published Vulnerability Notes
aimingoo的专栏
aimingoo的专栏
D
DataBreaches.Net
PCI Perspectives
PCI Perspectives
The Register - Security
The Register - Security
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
H
Hacker News: Front Page
Google DeepMind News
Google DeepMind News
有赞技术团队
有赞技术团队
The Last Watchdog
The Last Watchdog
GbyAI
GbyAI
L
Lohrmann on Cybersecurity
B
Blog
NISL@THU
NISL@THU
T
The Exploit Database - CXSecurity.com
Microsoft Azure Blog
Microsoft Azure Blog
博客园_首页
N
Netflix TechBlog - Medium
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
L
LangChain Blog
J
Java Code Geeks
SecWiki News
SecWiki News
博客园 - 三生石上(FineUI控件)
P
Privacy & Cybersecurity Law Blog

博客园 - 水言木

好久没来了,发个招聘贴 RavenDB Tips: 巧妙设计文档的Id格式以提升查询性能 CQRS实践(4): 领域事件 CQRS实践(3): Command执行结果的返回 CQRS实践(2): Command的实现 CQRS实践(1): 什么是CQRS 准备重新开始写点东西 不要让编写set访问器成为习惯 [PoEAA] Learning Notes of Data Transfer Object 再谈“引用” 使用UrlRewriter进行Url重写的完整解决方案 迅速搭建SVN环境 小议GridView中的删除按钮 关于Ajax的只言片语[2008.7.31最后更新] 重温:从aspx到dll 小记一次让我误会的引用传参 关于ASP.NET的只言片语[2008.8.12最后更新] .ctor,.cctor 以及 对象的构造过程 汶川地震小感
工厂的那些事儿
水言木 · 2008-07-06 · via 博客园 - 水言木

  下午考完试了,挺轻松的,不过现在不知道要干嘛了,随便写两句吧,也不知道要取个什么名字,就也时尚一下,叫成《工厂的那些事儿》吧 :)

  既然标题取成了工厂,那就是Factory Pattern了,前段时间看TerryLee大哥的工厂方法的文章,迷惑了几天,不过在某天早醒来的瞬间,我突然想通了,不过一直没有时间把它前下来,就趁这会儿有空,把它记录下来吧。

  First, 贴上TerryLee讲工厂方法那篇文章的地址:http://terrylee.cnblogs.com/archive/2006/01/04/310716.html

  下面引用的两段原文就是曾经引起我疑问的地方了:

Segment 1在应用程序中,我们要使用某一种日志记录方式,也许会用到如下这样的语句:
EventLog eventlog = new EventLog();
eventlog.Write();
当日志记录的方式从EventLog变化为FileLog,我们就得修改所有程序代码中出现上面语句的部分,这样的工作量是可想而知的。

Segment 2在应用程序中,Log对象的创建是频繁的,在这里我们可以把
LogFactory factory = new EventFactory();
这句话放在一个类模块中,任何需要用到Log对象的地方仍然不变。要是换一种日志记录方式,只要修改一处为:
LogFactory factory = new FileFactory();
其余的任何地方我们都不需要去修改。

  我曾一直想不通,如果把Segment 1中的 EventLog eventlog = new EventLog();改成Log log = new EventLog(),那会跟下面采用了Factory Method的情况会有多大的差别?大家都把变化范围缩小到了new的那一句,segment 1中只要 new EventLog()后,对后面的代码而言,都只是持有对抽象的Log的引用,segment 2中也一样,在后面都是持有对LogFactory这个抽象类的引用,大家的变化都在new的那一行,那引入工厂方法的意义在哪里?为什么TerryLee说Segment1中“这样的工作量是可想而知的”,而Segment中“只要修改一处”?

  带着这个疑问我用我笨重的大脑想了又想,终于在某一天早上醒来的瞬间想通了(好像我需要反醒我的智商了)。

  其实如果仅仅只是new了一个具体的日志类的话,引入工厂方法确实没有意义,如我的疑问中所说,两者的修改都只集中在对象的创建那一句,但是,如果我们在程序中需要用到十个不同的日志对象呢?在没有用工厂方法时,我们就要出现10次的Log log = new EventLog(),于是,依赖就开始在程序中遍布,一旦某天要改成文件日志,那就要在这10处修改,改成Log log = new FileLog()。

  而我们看看使用Factory Method的情形,首先创建一个工厂对象LogFactory logfactory = new EventLogFactory(),以后每次需要创建日志对象的时候,我们只需要:Log log = logFactory.Create(),为了得到10个不同的日志对象,我们只需要在创建工厂的那一行代码中依赖实现,其余地方都是依赖于抽象,一旦某日要换成文件日志,则只要在创建工厂的地方进行改动就可以了,相对于没有使用工厂方法的程序,耦合度的降低可想而知。

  如果在LogFactory logfactory = new EventLogFactory()这里利用反射来创建工厂,那就可以通过修改配置文件实现EventLog和FileLog以及将来要添加的日志记录器之间的更换,当然,你也可以想到在Segment1中使用反射,但如果这样的话,我们创建10个日志对象,就得在10个地方写上反射代码,而这些代码都是冗余的。

  总结一下,工厂方法引入后到底解决了什么问题?工厂工厂,从空面意思就可以想到,它一定跟创建大量的产品有关,就像上面的Segment1和Segment2,如果程序只需要一个日志对象(Log)就完事儿,那引入工厂方法反而多写了代码,没有意义,但是当要创建多个产品(Log)时,工厂的优势就出来了,他可以让耦合隔离到一行代码中,而Segment1中则不行。

  这是工厂方法,还有一种Design Pattern叫做Abstract Factory,大家都跟工厂有关,那也就是说,他们对大批量创建产品(对象)的情况是很有用的,但他跟工厂方法又不同,如上所述,工厂方法生产来生产去也就生产出了一种产品――日志对象,而抽象工厂相对于它,不同的地方就在于抽象工厂可以生厂“一系列”的产品,和和,看来抽象工厂的规模比较大,厂长也比较有钱咯。

  就像工厂方法一样,如果只是创建一个实例,工厂就没有什么太大意义(要是只创建一个,我自己手工做就好了,何必要去盖一个工厂来呢?钱太多了么?),抽象工厂的外观就像下面这样:

public abstract Factory {
    
public AbstractProductA CreateProductA();
    
public AbstractProductB CreateProductB();
    
public AbstractProductC CreateProductC();
    
//… …
}

  当然,各种的Product不能完全没有关系,要不然把牛头和马嘴放到一个工厂类中去生产,那好像就有点对不起“高内聚”大哥了哈。

  之后,要创建产品时,只要new一个继承了Factory的具体工厂,再不停的CreateProduct*(),就可以得到许多的产品了。

  总结一句,工厂方法和抽象工厂,前者只生产一种产品,而后者是生产一个产品系列。当然,如果本身产品种类就是多变的,今天要让工厂会生产ProductE,后天又要让工厂会生厂ProductM,那抽象工厂也无能为力了。

  THE END.