论坛首页 Java企业应用论坛

设计模式学习笔记JAVA 03(工厂模式)—2014_3_28

浏览 19735 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2014-04-04  

**************************************

简单工厂,工厂模式 对比



 

**************************************

虽然有点像,但是也要分清楚。

 

http://blog.csdn.net/superbeck/article/details/4446177

 

区别                                                                                                                                  

 

简单工厂 用来生产同一等级结构中的任意产品。(对于增加新的产品,无能为力)

工厂方法 :用来生产同一等级结构中的固定产品。(支持增加任意产品)  

 

简单工厂                                                                                                                            

 

简单工厂模式的工厂类一般是使用静态方法,通过接收的参数的不同来返回不同的对象实例。

 

不修改代码的话,是无法扩展的。



 

工厂方法                                                                                                                      

 

工厂方法是针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例。

 

在同一等级结构中,支持增加任意产品。

 


 

小结

★工厂模式中,重要的是工厂类,而不是产品类。产品类可以是多种形式,多层继承或者是单个类都是可以的。但要明确的,工厂模式的接口只会返回一种类型的实例,这是在设计产品类的时候需要注意的,最好是有父类或者共同实现的接口。

 

★使用工厂模式,返回的实例一定是工厂创建的,而不是从其他对象中获取的。

 

★工厂模式返回的实例可以不是新创建的,返回由工厂创建好的实例也是可以的。

  • 大小: 42.4 KB
  • 大小: 34.6 KB
  • 大小: 39.7 KB
0 请登录后投票
   发表时间:2014-04-04   最后修改:2014-04-04

************************************

简单工厂 工厂模式 比较 实例

 

************************************

http://www.blogjava.net/jiujiubuzui/articles/189707.html?opt=admin

 

简单工厂模式及实例                                                                             

简单工厂模式又叫静态工厂模式,顾名思义,它是用来实例化目标类的静态类。下面我主要通过一个简单的实例说明简单工厂及其优点

 

国家的体育总局,无论足球篮球还是乒乓球的运动员都必须在这里注册才能拿到 我们国家职业运动员牌照。一家体育俱乐部(比如篮球的广东宏远,足球的深圳健力宝,注:2008年的文章)想获得球员为自己俱乐部效力,就必须通过这个运动员协会。

 

“足球运动员”和“篮球运动员”(还有其他运动员)都实现“运动员”这个接口。而“运动员协会”就是一个简单工 厂类,它负责实例化“运动员”。我们这里的“俱乐部”就是一个客户端(Client)



 



 

public class 俱乐部 {

          private 运动员 守门员;

          private 运动员 后卫;

          private 运动员 前锋;

          public void test() {

                  this.前锋 = 体育协会.注册足球运动员();

                  this.后卫 = 体育协会.注册足球运动员();

                  this.守门员 = 体育协会.注册足球运动员();

                

                  守门员.跑();

                  后卫.跳();

          }

}

 

以上就是简单工厂模式的一个简单实例,读者应该想象不用接口不用工厂而把具体类暴露给客户端的那种混乱情形吧(就好像没了体育总局,各个俱乐部在市场上自己胡乱的寻找仔细需要的运动员),简单工厂就解决了这种混乱。

 

上例中如果增加 “乒乓球运动员”产品类,就必须相应的修改“体育协会”工厂类,增加个“注册乒乓球运动员”方法。所以可以看出,简单工厂模式是不满足OCP(开闭原则,Open-Closed Principle)的。



 

 

工厂方法模式及其实例                                                                                       

 

工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目或者一个独立模块而言)工厂类,而工厂方法模式有一组实现了相同接 口的工厂类。下面我们通过修改上一节的实例来介绍工厂方法模式。



 


 
 

public class 俱乐部 {

          private 运动员 守门员;

          private 运动员 后卫;

          private 运动员 前锋;

          public void test() {

                  体育协会 中国足协 = new 足球协会();

                

                  this.前锋 = 中国足协.注册();

                  this.后卫 = 中国足协.注册();

                  守门员.跑();

                  后卫.跳();

          }

}

 

很明显可以看到,“体育协会”工厂类变成了“体育协会”接口,而实现此接口的分别是“足球协会”“篮球协会”等等具体的工厂类。

 

这样做有什么好处呢?很明显,这样做就完全OCP了。如果需要再加入(或扩展)产品类(比如加多个“乒乓球运动员”)的话就不再需要修改工厂类了,而只需相应的再添加一个实现了工厂接口(“体育协会”接口)的具体工厂类。

从以上对两种模式的介绍可以了解到,工厂方法模式是为了克服简单工厂模式的缺点(主要是为了满足OCP)而设计出来的。

  • 大小: 49.4 KB
  • 大小: 34.8 KB
  • 大小: 43.5 KB
  • 大小: 43.5 KB
  • 大小: 56.5 KB
0 请登录后投票
   发表时间:2014-04-05  

****************************************

美国队长 当年 收藏的海报

 

美版《围炉夜话》

*****************************************



 



 

 



 



 

  • 大小: 63.6 KB
  • 大小: 82.6 KB
  • 大小: 30.9 KB
  • 大小: 81.8 KB
0 请登录后投票
   发表时间:2014-04-06  

**************************

原来还有一个原则

 

**************************

Let’s pretend you’ve never heard of an OO factory. Here’s a version of the PizzaStore that doesn’t use a factory; make a count of the number of concrete pizza objects this class is dependent on.

If you added California style pizzas to this PizzaStore, how many objects would it be dependent on then?

 

public class DependentPizzaStore {
public Pizza createPizza(String style, String type) {
Pizza pizza = null;
if (style.equals(“NY”)) {
if (type.equals(“cheese”)) {
pizza = new NYStyleCheesePizza();
} else if (type.equals(“veggie”)) {
pizza = new NYStyleVeggiePizza();
} else if (type.equals(“clam”)) {
pizza = new NYStyleClamPizza();
} else if (type.equals(“pepperoni”)) {
pizza = new NYStylePepperoniPizza();
}
} else if (style.equals(“Chicago”)) {
if (type.equals(“cheese”)) {
pizza = new ChicagoStyleCheesePizza();
} else if (type.equals(“veggie”)) {
pizza = new ChicagoStyleVeggiePizza();
} else if (type.equals(“clam”)) {
pizza = new ChicagoStyleClamPizza();
} else if (type.equals(“pepperoni”)) {
pizza = new ChicagoStylePepperoniPizza();
}
} else {
System.out.println(“Error: invalid type of pizza”);
return null;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}

 

Looking at object dependencies                                                      

 

When you directly instantiate an object, you are depending on its concrete class. Take a look at our very dependent PizzaStore one
page back. It creates all the pizza objects right in the PizzaStore class instead of delegating to a factory.

 

If we draw a diagram representing that version of the PizzaStore and all the objects it depends on, here’s what it looks like:



 

 

The Dependency Inversion Principle                                                


 

it even has a big, formal name: Dependency Inversion Principle.

 

Design Principle
Depend upon abstractions. Do not depend upon concrete classes.

At first, this principle sounds a lot like “Program to an interface, not an implementation,” right? It is similar;
however, the Dependency Inversion Principle makes an even stronger statement about abstraction.

It suggests that our high-level components should not depend on our low-level components; rather, they should both depend on abstractions.

 

Well, let’s start by looking again at the pizza store diagram on the previous page.

PizzaStore is our “high-level component” and the pizza implementations are our “lowlevel components,” and clearly the PizzaStore is dependent
on the concrete pizza classes.

 

Let’s think about how we’d apply this principle to our Very Dependent PizzaStore implementation...

 

 

Applying the Principle                                                                    

 

Now, the main problem with the Very Dependent PizzaStore is that it depends on every type of pizza because it actually instantiates concrete types in its orderPizza() method.

 

While we’ve created an abstraction, Pizza, we’re nevertheless creating concrete Pizzas in this code, so we don’t get a lot of leverage out of this abstraction.



 

After applying the Factory Method, you’ll notice that our high-level component, the PizzaStore, and our low-level components, the pizzas, both depend on Pizza, the abstraction.

 

Factory Method is not the only technique for adhering to the Dependency Inversion Principle, but it is one of the more powerful ones.

 

  • 大小: 67.9 KB
  • 大小: 55.9 KB
  • 大小: 71.3 KB
0 请登录后投票
   发表时间:2014-04-06  

********************************

数学系对 DIP 表 忠心

 

********************************

http://www.cnblogs.com/cbf4life/archive/2009/12/15/1624435.html

采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,减少并行开发引起的风险,提高代码的可读性和可维护性。

     证明一个定理是否正确,有两种常用的方法:一种是根据提出的论题,经过一番论证,推出和定理相同的结论,这是顺推证法;还有一种是首先假设提出的命题是伪 命题,然后推导出一个荒谬、与已知条件互斥的结论,这是反证法。我们今天就用反证法来证明依赖倒置原则是多么的优秀和伟光正!

     论题:依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,减少并行开发引起的风险,提高代码的可读性和维护性。

     反论题:不使用依赖倒置原则也可以减少类间的耦合性,提高系统的稳定性,减少并行开发引起的风险,提高代码的可读性和维护性。

     我们通过一个例子来说明反论题是不成立的。现在的汽车越来越便宜了,也就顶多一个卫生间的价格(学区房,不打折)就可以买到一辆不错的汽车,有汽车就必然有人来驾驶了,司机驾驶奔驰车的类图如图



 

public class Client {
 
public static void main(String[] args) {
 
Driver zhangSan = new Driver();
 
Benz benz = new Benz();
 
//张三开奔驰车
 
zhangSan.drive(benz);
 
}
 
}

 

通过以上的代码,完成了司机开动奔驰车的场景,到目前为止,这个司机开奔驰车的项目没有任何问题。我们常说“危难时刻见真情”,我们把这句话移植到技术上 就成了“变更才显真功夫”,业务需求变更永无休止,技术前进就永无止境,在发生变更时才能发觉我们的设计或程序是否是松耦合。

 

我们在一段貌似磐石的程序上 加上一块小石头:张三司机不仅要开奔驰车,还要开宝马车,又该怎么实现呢?

 

public class BMW {
 
//宝马车当然也可以开动了
 
public void run(){
 
System.out.println("宝马汽车开始运行...");
 
}
 
}

 宝马车也产生了,但是我们却没有办法让张三开动起来,为什么?张三没有开动宝马车的方法呀!



 

我们的设计出现了问题:司机类和奔驰车类之间是一个紧耦合的关系,其导致的结果就是系统的可维护性大大降低,可读性降低,两个相似的类需要阅读两个文件,你乐意吗?

 

证明到这里,我们已经知道伪命题已经部分不成立了。

 

     我们继续证明,“减少并行开发引起的风险”,什么是并行开发的风险?并行开发最大的风险就是风险扩散,本来只是一段程序的错误或异常,逐步波及一个功能, 一个模块,甚至到最后毁坏了整个项目,为什么并行开发就有这个风险呢?一个团队,20人开发,各人负责不同的功能模块,甲负责汽车类的建造,乙负责司机类 的建造,在甲没有完成的情况下,乙是不能完全地编写代码的,缺少汽车类,编译器根本就不会让你通过!在缺少Benz类的情况下,Driver类能编译吗? 更不要说是单元测试了!在这种不使用依赖倒置原则的环境中,所有的开发工作都是“单线程”的,甲做完,乙再做,然后是丙继续…,这在90年代“个人英雄主 义”编程模式中还是比较适用的,一个人完成所有的代码工作,但在现在的大中型项目中已经是完全不能胜任了,一个项目是一个团队的协作结果,一个“英雄”再 牛X也不可能了解所有的业务和所有的技术,要协作就要并行开发,要并行开发就要解决模块之间的项目依赖关系,那然后呢?依赖倒置原则就隆重出场了!(批注,作者上小学时曾骂哭过好几个老师)



 

司机类的实现

public class Driver implements IDriver{
 
//司机的主要职责就是驾驶汽车
 
public void drive(ICar car){
 
car.run();
 
}
 
}

 

汽车两个实现类

public class Benz implements ICar{
 
//汽车肯定会跑
 
public void run(){
 
System.out.println("奔驰汽车开始运行...");
 
}
 
}
 
public class BMW implements ICar{
 
//宝马车当然也可以开动了
 
public void run(){
 
System.out.println("宝马汽车开始运行...");
 
}
 
}

 

在业务场景中,我们贯彻“抽象不应该依赖细节”,也就是我们认为抽象(ICar接口)不依赖BMW和Benz两个实现类(细节),因此我们在高层次的模块中应用都是抽象,Client的实现过程如代码

public class Client {

public static void main(String[] args) {

IDriver zhangSan = new Driver();

ICar benz = new Benz();

//张三开奔驰车

zhangSan.drive(benz);

}

} 

 

当然,张三如果要开宝马车,也很容易,我们只要修改业务场景类就可以

ICar bmw = new BMW();
 
//张三开宝马
 
zhangSan.drive(bmw);

 
 


  • 大小: 45.5 KB
  • 大小: 67.2 KB
  • 大小: 41.1 KB
  • 大小: 42.1 KB
0 请登录后投票
   发表时间:2014-04-07  

**********************************

校花的困惑 2

 

***********************************



 



 



 



 



 



 

Close. But to do that you’ll have to rely on a factory to get those concrete classes out of your Pizza Store.

 

Once you’ve done that, your different concrete pizza types depend only on an abstraction and so does your store.

We’ve taken a design where the store depended on concrete classes and inverted those dependencies (along with your thinking).

  • 大小: 48 KB
  • 大小: 68.7 KB
  • 大小: 56.5 KB
  • 大小: 66.7 KB
  • 大小: 45.1 KB
  • 大小: 53.7 KB
0 请登录后投票
   发表时间:2014-04-08  

**********************

依赖倒置原则 的 升华

 

源自我国的 创新

**********************



 

最近听到 很误导 小朋友 的话,就是 摘下面具,做回自己。

 

不得不讲个故事了,



 



 

带上面具,才能游刃有余,牺牲别人,成全自己。

 

 

面具的好处很多,但是有一个缺点:会 真得 把自己 给忘记了。

 

像小白 一样找回自己的人比中 彩票还难。


 



 

  • 大小: 59.9 KB
  • 大小: 60.1 KB
  • 大小: 1.1 MB
  • 大小: 30.5 KB
  • 大小: 21.4 KB
0 请登录后投票
   发表时间:2014-04-10  

************************

the enemy

 

************************

Meanwhile, back at the PizzaStore...

 

The design for the PizzaStore is really shaping up: it’s got a flexible framework and it does a good job of adhering to design principles.

 

 We have met the enemy, and they are us                                   







We’ve got the same product families (dough, sauce, cheese, veggies, meats) but different implementations based on region.



 

Families of ingredients...                                                      

 

New York uses one set of ingredients and Chicago another.
Given the popularity of Objectville Pizza it won’t be long before you also need to ship another set of regional ingredients to California, and what’s next? Seattle?



 

Each family consists of a type of dough, a type of sauce, a type of cheese, and a seafood topping (along with a few more we haven’t shown, like veggies and spices).

 

Building the ingredient factories                                          

 

Let’s start by defining an interface for the factory that is going to create all our ingredients:



 

Here’s what we’re going to do:

  1. Build a factory for each region. To do this, you’ll create a subclass of PizzaIngredientFactory that implements each create method
  2. Implement a set of ingredient classes to be used with the factory, like ReggianoCheese, RedPeppers, and ThickCrustDough. These classes can be shared among regions where appropriate.
  3. Then we still need to hook all this up by working our new ingredient factories into our old PizzaStore code.

Building the New York ingredient factory                                            



 

The NY ingredient factory implements the interface for all ingredient factories.

For each ingredient in the ingredient family, we create the New York version.

 

Reworking the pizzas...                                                                      



 

Reworking the pizzas, continued...                                            

 

When we wrote the Factory Method code, we had a NYCheesePizza and a ChicagoCheesePizza class.

If you look at the two classes, the only thing that differs is the use of regional ingredients.

The pizzas are made just the same (dough + sauce + cheese).

The same goes for the other pizzas: Veggie, Clam, and so on.

They all follow the same preparation steps; they just have different ingredients.

 

So, what you’ll see is that we really don’t need two classes for each pizza; the ingredient factory is going to handle the regional differences for us.



 

To make a pizza now, we need a factory to provide the ingredients.

So each Pizza class gets a factory passed into its constructor, and it’s stored in an instance variable.

 

The prepare() method steps through creating a cheese pizza, and each time it needs an ingredient, it asks the factory to produce it.



 

 

Revisiting our pizza stores                                                            



 

The NY Store is composed with a NY pizza ingredient factory.

This will be used to produce the ingredients for all NY style pizzas.

 

We now pass each pizza the factory that should be used to produce its ingredients.

 

For each type of Pizza, we instantiate a new Pizza and give it the factory it needs to get its ingredients.

 

 

What have we done?                                                                



 

That was quite a series of code changes; what exactly did we do?

 

We provided a means of creating a family of ingredients for pizzas by introducing a new type of factory called an Abstract Factory.

 

An Abstract Factory gives us an interface for creating a family of products.

By writing code that uses this interface, we decouple our code from the actual factory that creates the products.
That allows us to implement a variety of factories that produce products meant for different contexts – such as different regions, different operating systems, or different look and feels.

 

Because our code is decoupled from the actual products, we can substitute different factories to get different behaviors (like
getting marinara instead of plum tomatoes).

 

 

  • 大小: 82.2 KB
  • 大小: 59.8 KB
  • 大小: 202.2 KB
  • 大小: 62.4 KB
  • 大小: 83.7 KB
  • 大小: 74.4 KB
  • 大小: 71.6 KB
  • 大小: 87.7 KB
  • 大小: 75 KB
  • 大小: 83.4 KB
  • 大小: 51.5 KB
0 请登录后投票
   发表时间:2014-04-11  

**************************************

烧饼是怎么来的 2

 

抽象工厂流程

**************************************

 

Taylor and Justin can’t get enough Object ville Pizza!

What they don’t know is that now their orders are making use of the new ingredient factories.

So now when Taylor orders...



 



 



 



 



 



 



 

 

  • 大小: 40.8 KB
  • 大小: 64.3 KB
  • 大小: 46.1 KB
  • 大小: 46.8 KB
  • 大小: 64 KB
  • 大小: 65.9 KB
  • 大小: 50.9 KB
0 请登录后投票
   发表时间:2014-04-12  

**************************************************************

利用吃饭 来理解 简单工厂、工厂模式 和 抽象工厂

 

一个单身  程序员 进入中 国 梦 后

**************************************************************

http://hi.baidu.com/laocui172/item/0211be1ca50c3af487ad4ed6

以下只是被copy 作者个人言论,不代表本学习笔记观点

 

简单工厂模式生活例子 吃饭是人的基本需求,如果人类不需要吃饭,可能我们就能活得清闲许多,也就不需要像现在一样没日没夜的工作,学习。我们学习是为了找到更好的工作,好工作 为了赚更多的钱,最终为了吃饱饭,吃好饭。因此可以说吃饭是与人息息相关,下面就从吃饭的例子来引入工厂模式的学习。

   如果你想吃饭了,怎么办自己做吗?自己做就相当于程序中直接使用new。当然是自己下个指令,别人来做更爽。那就把做饭的任务交给你的老婆吧,那么她就是 一个做饭的工厂了,你告诉她要要吃红烧肉,等会她就从厨房给你端出来一盘香喷喷的红烧肉了,再来个清蒸鱼吧,



 

工厂方法模式生活例子:    人是最贪得无厌的动物,老婆手艺再好,总有不会做的菜,你想吃回锅肉,怎么办,让老婆学呗,于是就给她就新增了做回锅肉的方法,以后你再想吃一个新菜,就 要给你老婆新加一个方法,显然用老婆做菜的缺点也就暴露出来了,用程序设计的描述就是对修改永远不能封闭。当然优点也是有的,你有了老婆这个工厂,这些菜 不用你自己做了,只要直接调用老婆这个工厂的方法就可以了。

   面对上面对修改不能封闭的问题,有没有好的解决方案吗,如果你有钱,问题就迎刃而解了,把老婆抽象变成一个基类,你多娶几个具体的老婆,分别有做鱼 的,做青菜的,炖汤的老婆,如果你想吃一个新菜,就再新找个女人,从你的老婆基类继承一下,让她来做这个新菜。显然多多的老婆这是所有男人的梦想,没有办 法,法律不允许,那么咱们只是为了做饭,老婆这个抽象类咱们不叫老婆了,叫做厨师吧,她的子类也自然而然的该叫做鱼的厨师、炖汤的厨师了。现在来看这个模 式发生了变化,结构中多了一个厨师的抽象,抽象并不具体的加工产品了,至于是炖汤还是炖鱼,是由这个抽象工厂的继承子类来实现,现在的模式也就变成工厂方 法模式了,

 

实现了一个变化

 

抽象工厂模式生活例子     世事多变,随着时间的推移,走过的地方越来越多,你天南海北的朋友也越来越多。你发现菜原来还分了许多菜系,鲁菜、粤菜、湘菜等等,它们各有各的风味,同 样是红烧肉由不同菜系出来的味道也各不相同, 你招待不同的朋友要用不同的菜系,这下难办了,你的厨师都是鲁菜风味,怎么办,广东的朋友来了吃不惯。现在我们再回到简单工厂模式(就是老婆做菜的模 式),我们把红烧肉再向下继承,生成鲁菜红烧肉、粤菜红烧肉、湘菜红烧肉;清蒸鱼向下继承为鲁菜清蒸鱼、粤菜清蒸鱼、湘菜清蒸鱼,其它也以此类推。我们也 修改一下老婆的这个类,不让其返回食物基类,而是返回红烧肉、清蒸鱼、爆炒空心菜、西红柿鸡蛋汤这一层次,并把这些方法抽象化,作为菜系工厂基类,然后再 从此基类继承出,鲁菜工厂、粤菜工厂、湘菜工厂等等,再由这些具体工厂实现创建具体菜的工作,哈哈你如果招待广东朋友就用粤菜工厂,返回的就是一桌粤菜菜 系的红烧肉、清蒸鱼、空心菜和西红柿鸡蛋汤了,你的广东朋友一定会吃的非常合乎胃口了。噢,非常好,你已经实现了抽象工厂模式了。

 

改成 中餐、西餐

 

  • 大小: 63.7 KB
  • 大小: 115.9 KB
  • 大小: 82.5 KB
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics