|
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
|---|---|
| 作者 | 正文 |
|
时间:2008-01-30 关键字: 设计模式
当看到"new",就会想到"具体","new"有什么不对劲的? pizza orderPizza(){
Pizza piz = new Pizza();
//为了让系统有弹性,我们很希望这是一个抽象类或接口,但如果这样,这些类或接口就无法直接实例化
piz.prepare();
piz.bake();
piz.cut();
piz.box();
return piz;
}
但是你需要更多的披萨类型,所以必须增加一些代码,来决定适合的披萨类型,然后再制造这个披萨: pizza orderPizza(String type){
//现在把披萨类型传入orderPizza
Pizza piz;
//根据披萨的类型,实例化正确的具体类,注意这里的任何披萨都必须实现Pizza接口
if(type.equals("cheese")){
piz = new CheesePizza();
}else if(type.equals("greek")){
piz = new GreekPizza();
}
//某一天你为了赶上竞争者,你加入了一些流行风味的披萨,greek披萨卖的不好,你要从菜单去掉,随着时间的过去,这里就必须一改再改
else if(type.equals("clam")){
piz = new ClamPizza();
}
else if(type.equals("veggie")){
piz = new VeggaePizza();
}
//一旦我们有了一个披萨,需要做一些准备,然后烘烤.切片.装盒,这里是我们不想改变的地方
piz.prepare();
piz.bake();
piz.cut();
piz.box();
return piz;
}现在我们知道哪些会改变哪些不会改变,该是使用封装的时候了,现在我们把创建对象的代码抽离,建立一个简单披萨工厂,这个工厂只管如何创建披萨: public class SimplePizzaFactory {
//内定一个createPizza()方法,所有客户通过这个方法来实例化新对象
public Pizza createPizza(String type) {
Pizza pizza = null;
//移植过来的代码,基本没什么变动
if (type.equals("cheese")) {
pizza = new CheesePizza();
} else if (type.equals("pepperoni")) {
pizza = new PepperoniPizza();
} else if (type.equals("clam")) {
pizza = new ClamPizza();
} else if (type.equals("veggie")) {
pizza = new VeggiePizza();
}
return pizza;
}
}
这么做有什么好处?似乎只是把问题搬到另一个对象罢了,问题依然存在. public class PizzaStore {
//加一个SimplePizzaFactory的引用
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) {
this.factory = factory;
}
public Pizza orderPizza(String type) {
Pizza pizza;
//而orderPizza()方法通过简单传入订单类型来使用工厂创建披萨,
//请注意,我们把new操作符替换成工厂对象的创建方法,这里不在使用具体实例化
pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
//...other methon
}简单工厂其实不是一个设计模式,反而比较像是一种编程习惯,接下来继续用披萨店来讲述工厂方法模式. //现在PizzaStore是抽象的,每个子类都会覆盖createPizza方法,同时使用PizzaStore定义的orderPizza方法,
//甚至可以把orderPizza定义为tinal,以防止被之类覆盖
public abstract class PizzaStore {
/**
*现在把工厂对象移到这个方法中,工厂方法现在是抽象的,所以依赖子类来处理对象的创建
*工厂方法必须返回一个产品,超类中定义的方法,通常使用到工厂方法的返回值
*工厂方法将客户(如orderPizza)和实际创建具体产品的代码分割开来
*/
abstract Pizza createPizza(String type);
public Pizza orderPizza(String type) {
//现在createPizza()方法从工厂对象中移回PizzaStore
Pizza pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
好了,让我们把纽约风味的加盟店开起来吧: //createPizza()返回一个Pizza对象,由子类全权负责该实例化哪一个具体Pizza
public class NYPizzaStore extends PizzaStore {
//必须实现的createPizza方法
Pizza createPizza(String item) {
if (item.equals("cheese")) {
return new NYStyleCheesePizza();
} else if (item.equals("veggie")) {
return new NYStyleVeggiePizza();
} else if (item.equals("clam")) {
return new NYStyleClamPizza();
} else if (item.equals("pepperoni")) {
return new NYStylePepperoniPizza();
} else return null;
}
}
实现一下披萨本身,没披萨开什么加盟店呢: //从一个抽象披萨类开始,所有的具体披萨都必须派生自这个类
public abstract class Pizza {
String name; //每个披萨都有名称,面团类型,一套佐料
String dough;
String sauce;
ArrayList toppings = new ArrayList();
void prepare() {
System.out.println("Preparing " + name);
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
System.out.println("Adding toppings: ");
//准备工作需要以特定的顺序进行
for (int i = 0; i < toppings.size(); i++) {
System.out.println(" " + toppings.get(i));
}
}
void bake() {}
void cut() {}
void box() {}
public String getName() {return name;}
public String toString() {
StringBuffer display = new StringBuffer();
display.append("---- " + name + " ----\n");
display.append(dough + "\n");
display.append(sauce + "\n");
for (int i = 0; i < toppings.size(); i++) {
display.append((String )toppings.get(i) + "\n");
}
return display.toString();
}
}
现在我们来定义纽约和芝加哥风味的具体子类,并吃些披萨怎么样: public class NYStyleCheesePizza extends Pizza {
public NYStyleCheesePizza() {
name = "NY Style Sauce and Cheese Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";
toppings.add("Grated Reggiano Cheese");
}
}
public class ChicagoStyleCheesePizza extends Pizza {
public ChicagoStyleCheesePizza() {
name = "Chicago Style Deep Dish Cheese Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
toppings.add("Shredded Mozzarella Cheese");
}
//这个芝加哥风味披萨覆盖cut()方法,将披萨切成正方形
void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
public class PizzaTestDrive {
public static void main(String[] args) {
//建立2个不同的店
PizzaStore nyStore = new NYPizzaStore();
PizzaStore chicagoStore = new ChicagoPizzaStore();
//下订单
Pizza pizza = nyStore.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("cheese");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
}
}认识工厂方法模式的时刻终于到了,工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪个.工厂方法让类把实例化推迟到子类 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
时间:2008-02-15
简单工厂模式的缺点是:当我们添加新产品时,需要更改工厂类。有点不附合开闭原则。
楼主继续把其他的设计模式的见解发出来。让我们这些菜鸟能学习 |
|
| 返回顶楼 | |
|
时间:2008-02-15
关注焦点转移?
PS:楼上用工厂来作新产品有点浪费.... 不如用状态位来区分产品 工厂是用在方法实现上有区别的业务类中的. |
|
| 返回顶楼 | |
|
时间:2008-03-28
楼主写的太好了,很深刻.明白的很多,thank you
|
|
| 返回顶楼 | |
|
时间:2008-03-28
head first 设计模式
|
|
| 返回顶楼 | |
|
时间:2008-03-30
gznofeng 写道 简单工厂模式的缺点是:当我们添加新产品时,需要更改工厂类。有点不附合开闭原则。
楼主继续把其他的设计模式的见解发出来。让我们这些菜鸟能学习 抽象工厂模式 优点:对产品的增加支持OCP原则,缺点:对产品系列的增加不支持OCP原则, |
|
| 返回顶楼 | |
|
时间:2008-04-16
设计模式归根结底是用来解耦的。。。。。。但是java语言的性质约束了在代码上肯定会有开始那一点,是用new来完成的。我们可以用不同的模式来隐藏它。但是它们之间的相互依赖是不能真正消除的。同时,我觉得如果依赖关系做的简单明了,到也不是坏事。毕竟,对于面向OO编程来说,如果能够将现实中的一个场景或是一个领域映射到java中的class中的话,把其中的一些new给去掉,而使用模式给隐藏掉的话,代码会不会难于理解。
楼主说的一句话很好:“模式其实是一种编程习惯”,正如一个正常人在现实中会做什么一样,这些模式正是模拟了这些。当我们真正理解面向OO,并具有OO的思想以后,这些应该都不是问题。 |
|
| 返回顶楼 | |
|
时间:2008-05-28
忍不住要说一下。完全搞错了。工厂方法不是这个样子的。你们不要看阎宏的垃圾教材。他根本算不上合格的架构师。一个工厂模式都搞不明白,道德经,乱七八糟的比喻倒是一套一套的。
工厂方法,是不应该暴露实现类的名称的。 Factory.CreateProduct("A");跟new A()相比,根本就没有区别。只不过是限制了A可以被看到的方法而已。 这样用模式,叫脱裤子放P。 工厂模式搞不清楚,后面都是白扯。不忍心见你们在错误的道路上越走越远,特地出来指点。 |
|
| 返回顶楼 | |
|
时间:2008-05-29
不能说错,这个例子本身是为了解释工厂模式的理论,它只是列举了一种可能性。
Pizza createPizza(String type)可以改成 Pizza createPizza(PizzaType type); 或 Pizza createPizza(int type); 可由程序员自己另外封装确定判断生成类,用String是为了方便阅读理解。 OO解耦是思维模式,设计模式的书不是“21天学会java”,教给你的是指导思想,代码不能Copy & Paste. |
|
| 返回顶楼 | |
|
时间:2008-05-29
另:
已经有人指出楼主的代码来自HEAD FIRST DESIGN PATTERN,虽然中文部分有楼主努力,但是否应该说明这Code是引用? |
|
| 返回顶楼 | |









