Blog信息 |
blog名称: 日志总数:1304 评论数量:2242 留言数量:5 访问次数:7591080 建立时间:2006年5月29日 |

| |
[设计模式]Java中的模式 --工厂模式 软件技术
lhwork 发表于 2006/12/19 9:36:28 |
工厂模式主要负责将大量有共通接口的类实例化,工场模式有以下几种形态简单工厂(Simple Factory) 又称 静态工厂方法(Static Factory Method)工厂方法(Factory Method) 又称 多态性工厂(Polymorphic Factory)抽象工厂(Abstract Factory) 又称 工具箱(Kit or Toolkit)
先说简单工厂模式:需求:一个水果工厂,为任何来的客人提供水果,现有水果Apple ,Banana,Orange实现:定义三个类Apple,Banana,Orange 让他们都实现Fruit接口
500)this.width=500'>
-----------------------
list
1
--------------------------------
500)this.width=500'>
500)this.width=500'>
public
class
FruitFactory
500)this.width=500'>
{500)this.width=500'>500)this.width=500'>
public
static
Fruit factory(String which)
500)this.width=500'>
{500)this.width=500'>500)this.width=500'>
if
(which.equalsIgnoreCase(
"
apple
"
)
500)this.width=500'>
{500)this.width=500'> return new Apple();500)this.width=500'>500)this.width=500'> }
else
if
(which equalsIgnoreCase(
"
banana
"
))
500)this.width=500'>
{500)this.width=500'> return new Banana();500)this.width=500'>500)this.width=500'> }
else
if
(which equalsIgnoreCase(
"
orange
"
))
500)this.width=500'>
{500)this.width=500'> return new Orange();500)this.width=500'>500)this.width=500'> }
else
500)this.width=500'>
{500)this.width=500'>
throw
RuntimeException(
"
no this fruit
"
);500)this.width=500'> }
500)this.width=500'> }
500)this.width=500'>}
500)this.width=500'>
-----------------------
list
1
--------------------------------
500)this.width=500'>
客人的需求实现
1
500)this.width=500'>
500)this.width=500'>
try
500)this.width=500'>
{
2
500)this.width=500'> FruitFactory.factory(
"
apple
"
);
3
500)this.width=500'> FruitFactory.factory(
"
banana
"
);
4
500)this.width=500'> FruitFactory.factory(
"
orange
"
);
5
500)this.width=500'>
500)this.width=500'>}
catch
(Exception e)
500)this.width=500'>
{
6
500)this.width=500'> 500)this.width=500'>500)this.width=500'>
7
500)this.width=500'>}
8
500)this.width=500'>
优点:分开了生产者和消费者的责任缺点:所有的产品都出自一个工厂造成问题:1,当这个工厂出现问题时,损失惨重,不利于分散风险2,当出现不同种类的水果(有不同接口的水果),工场内部既须要判断种类,又须要判断具体的产品。比如这种结构:1,水果接口Fruit2,两个种类水果实现了Fruit接口 有籽水果 /无籽水果3,所有有籽水果继承自有籽水果类 ,所有无籽水果继承自无籽水果类
这事如果客户要有籽西瓜,无籽西瓜 工厂类的实现
1
500)this.width=500'>
-----------------------
list
2
--------------------------------
2
500)this.width=500'>
500)this.width=500'>
public
class
FruitFactory
500)this.width=500'>
{
3
500)this.width=500'>
500)this.width=500'>
public
static
Fruit factory(String which,
boolean
hasSeed )
500)this.width=500'>
{
4
500)this.width=500'>
500)this.width=500'>
if
(hasSeed)
500)this.width=500'>
{
5
500)this.width=500'>
500)this.width=500'>
if
(which.equalsIgnoreCase(
"
watermelon
"
)
500)this.width=500'>
{
6
500)this.width=500'>
return
new
WatermelonOne();
7
500)this.width=500'>
500)this.width=500'> }
else
if
(which equalsIgnoreCase(
"
orange
"
))
500)this.width=500'>
{
8
500)this.width=500'>
return
new
OrangeOne();
9
500)this.width=500'>
500)this.width=500'>
else
500)this.width=500'>
{
10
500)this.width=500'>
throw
RuntimeException(
"
no this fruit
"
);
11
500)this.width=500'> }
12
500)this.width=500'>
500)this.width=500'> }
else
500)this.width=500'>
{
13
500)this.width=500'>
500)this.width=500'>
if
(which.equalsIgnoreCase(
"
watermelon
"
)
500)this.width=500'>
{
14
500)this.width=500'>
return
new
WatermelonTwo();
15
500)this.width=500'>
500)this.width=500'> }
else
if
(which equalsIgnoreCase(
"
orange
"
))
500)this.width=500'>
{
16
500)this.width=500'>
return
new
OrangeTwo();
17
500)this.width=500'>
500)this.width=500'>
else
500)this.width=500'>
{
18
500)this.width=500'>
throw
RuntimeException(
"
no this fruit
"
);
19
500)this.width=500'> }
20
500)this.width=500'> }
21
500)this.width=500'> }
22
500)this.width=500'>}
23
500)this.width=500'>
-----------------------
list
2
--------------------------------
24
500)this.width=500'>
接着试想一下,我有20个大分类,复杂的层次结构,那么这个工厂模式怎么维护。总结一下:简单工厂方法,在一定程度上支持了开闭原则,当增加一种水果的时候符合开闭原则 但当增加一类水果(多种有共通特点的水果)时候,出现维护困难的问题。 这个时候引入工厂方法,工厂方法利用继承,解决了上边的问题。看看它是如何解决的。简单来说:工厂方法就是为没一大类水果实现一个"简单工厂",这些"简单工厂"都实现一个共通的接口。这样当然就解决了问题,添加一个大类的话,就添加一个简单工厂
在我们的日常生活中经常会遇到这样的情况,如要生产IBM-PC或者Apple ,每一台计算计又有Cpu和内存IBM-PC Apple,Cpu 内存Ram 不是一类东西,这个时候如果简单的建立四个工厂类是不对的。解决办法:
1
500)this.width=500'>
-----------------------
list
3
--------------------------------
2
500)this.width=500'>
500)this.width=500'>
public
IbmPcFactory
500)this.width=500'>
{
3
500)this.width=500'>
500)this.width=500'>
public
Cpu CpuFactory(String cpuType)
500)this.width=500'>
{
4
500)this.width=500'>
return
new
IbmPcCpu(cpuType);
5
500)this.width=500'> }
6
500)this.width=500'>
500)this.width=500'>
public
Ram RamFactory(String ramType)
500)this.width=500'>
{
7
500)this.width=500'>
return
new
IbmPcRam(ramType);
8
500)this.width=500'> }
9
500)this.width=500'>}
10
500)this.width=500'>
500)this.width=500'>
public
AppleFactory()
500)this.width=500'>
{
11
500)this.width=500'>
500)this.width=500'>
public
Cpu CpuFactory(String cpuType)
500)this.width=500'>
{
12
500)this.width=500'>
return
new
AppleCpu(cpuType);
13
500)this.width=500'> }
14
500)this.width=500'>
500)this.width=500'>
public
Ram RamFactory(String ramType)
500)this.width=500'>
{
15
500)this.width=500'>
return
new
AppleRam(ramType);
16
500)this.width=500'> }
17
500)this.width=500'>}
18
500)this.width=500'>
-----------------------
list
3
--------------------------------
19
500)this.width=500'>
这个就使抽象工厂了,不过抽象工厂对开闭原则的支持不够好,只在机型的增加上支持开闭,在配件上就不行了。
对比三个工厂模式,<<Java与模式>>的作者的比喻更能让人明白问题。
1,话说女娲造人,开始用手捏,感觉太慢2,所以女娲想出了办法,用一条绳子(简单工厂,告诉绳子怎么造人),放到泥堆里边,然後一抖,就出来一批人(简单工厂须要一个接口,interface 人)3,接着女娲想要男人和女人之分,所以造了两条绳子,阳绳和阴绳(工厂方法,两个工厂,告诉阳绳怎么造男人,女绳怎么造女人),然後一下出来一批男人,一批女人(工厂方法须要多个接口,interface 人 interface 绳 阳绳-阴绳实现绳 男人-女人实现人)4,可女娲还想造点动物,而且动物也想分男女(其实应改是雌雄),那怎么办,改造两条绳子,让绳子也学会怎么造动物(抽象工厂),这个时候抖一下绳子,阳绳出来的东西,长的像人的是男人,长的像动物的是雄动物,(抽象工厂须要再多的接口 interface 人 interface 兽 interface 绳阳绳-阴绳实现绳 男人-女人实现人 雌动物-雄动物实现兽)阴绳出来的东西,长的像人的是女人,长的像动物的是雌动物
最后再回到实现上,看到在list 1中,出现了大量的if(which.equalsIgnoreCase("xxx"){ return new Xxx();}试想如果产品上千,上万呢。那这个将是不可想想的。Java的动态load正好解决了这个问题看看实现
1
500)this.width=500'>
500)this.width=500'>
public
class
FruitFactory
500)this.width=500'>
{
2
500)this.width=500'>
500)this.width=500'>
public
static
Fruit factory(String which)
500)this.width=500'>
{
3
500)this.width=500'>
500)this.width=500'>
try
500)this.width=500'>
{
4
500)this.width=500'> Class clazz
=
Class.forName(which);
5
500)this.width=500'>
return
(Fruit)clazz.newInstance();
6
500)this.width=500'>
500)this.width=500'> }
catch
(Exception e)
500)this.width=500'>
{
7
500)this.width=500'> 500)this.width=500'>500)this.width=500'>
8
500)this.width=500'> }
9
500)this.width=500'> }
10
500)this.width=500'>}
11
500)this.width=500'>
好了,这个时候无论增加多少类的产品都不是问题了,你只要让所有的产品实现Fruit接口,同时为每个产品编写自己的类。完全符合开闭原则。
|
|
|