题记:写这篇博客要主是加深自己对产品模式的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢。
一、问题
在前一章《。。。。》中通过披萨的实例介绍了简略工厂模式。在披萨实例中,如果我想根据地域的不同生产出不同口味的披萨,如纽约口味披萨,芝加哥口味披萨。如果利用简略工厂模式,我们须要两个不同的工厂,NYPizzaFactory、ChicagoPizzaFactory。在该地域中有很多的披萨店,他们并不想依照总店的制作流程来生成披萨,而是希望采用他们自己的制作流程。这个时候如果还应用简略工厂模式,因为简略工厂模式是将披萨的制作流程完整承包了。那么怎么办?
二、解决方案
我们可以这样解决:将披萨的制作方法交给各个披萨店实现,但是他们只能供给制作实现的披萨,披萨的订单处理仍然要交给披萨工厂去做。也就是说,我们将createPizza()方法放回到PizzaStore中,其他的部份还是保持稳定。
三、基本定义
工厂方法模式定义了一个创建对象的接口,但由子类决议要实例化的类是哪个。工厂方法模式让实例化推迟到子类。
四、模式结构
工厂方法模式的UML结构图:
Product:抽象产品。所有的产品必须实现这个独特的接口,这样一来,应用这些产品的类既可以引用这个接口。而不是详细类。
ConcreteProduct:详细产品。
Creator:抽象工厂。它实现了所有操纵产品的方法,但不实现工厂方法。Creator所有的子类都必须要实现factoryMethod()方法。
ConcreteCreator:详细工厂。制造产品的实际工厂。它负责创建一个或者多个详细产品,只有ConcreteCreator类知道如何创建这些产品。
工厂方法模式是简略工厂模式的延伸。在工厂方法模式中,核心工厂类不在负责产品的创建,而是将详细的创建工作交给子类去实现。也就是后所这个核心工厂仅仅只是供给创建的接口,详细实现方法交给继承它的子类去实现。当我们的系统须要增加其他新的对象时,我们只须要添加一个详细的产品和它的创建工厂即可,不须要对原工厂进行任何修改,这样很好地符合了“开闭准则”。
五、工厂方法模式实现
针对下面的解决方案,失掉如下UML结构图:
抽象产品类:Pizza.java
public abstract class Pizza {
protected String name; //名称
protected String dough; //面团
protected String sause; //酱料
protected List<String> toppings = new ArrayList<String>(); //佐料
public void prepare() {
System.out.println("Preparing "+name);
System.out.println("Tossing dough");
System.out.println("Adding sause");
System.out.println("Adding toppings");
for(int i = 0;i < toppings.size();i++){
System.out.println(" "+toppings.get(i));
}
}
public void bake() {
System.out.println("Bake for 25 minutes at 350");
}
public void cut() {
System.out.println("Cutting the pizza into diagonal slices");
}
public void box() {
System.out.println("Place pizza in official PizzaStore box");
}
public String getName(){
return name;
}
}
详细产品类:NYStyleCheesePizza.java
public class NYStyleCheesePizza extends Pizza{
public NYStyleCheesePizza(){
name = "Ny Style Sauce and Cheese Pizza";
dough = "Thin Crust Dough";
sause = "Marinara Sauce";
toppings.add("Crated Reggiano Cheese");
}
}
ChicagoStyleCheesePizza.java
public class ChicagoStyleCheesePizza extends Pizza {
public ChicagoStyleCheesePizza(){
name = "Chicago Style Deep Dish Cheese Pizza";
dough = "Extra Thick Crust Dough";
sause = "Plum Tomato Sauce";
toppings.add("Shredded Mozzarella Cheese");
}
public void cut(){
System.out.println("Cutting the Pizza into square slices");
}
}
只有启程,才会到达理想和目的地,只有拼搏,才会获得辉煌的成功,只有播种,才会有收获。只有追求,才会品味堂堂正正的人。
抽象工厂:披萨总店。PizzaStore.java
public abstract class PizzaStore {
public Pizza orderPizza(String type){
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
/*
* 创建pizza的方法交给子类去实现
*/
abstract Pizza createPizza(String type);
}
详细工厂。披萨分店。NYPizzaStore.java
public class NYPizzaStore extends PizzaStore{
@Override
Pizza createPizza(String item) {
Pizza pizza = null;
if("cheese".equals(item)){
pizza = new NYStyleCheesePizza();
}
else if("veggie".equals(item)){
pizza = new NYStyleVeggiePizza();
}
else if("clam".equals(item)){
pizza = new NYStyleClamPizza();
}
else if("pepperoni".equals(item)){
pizza = new NYStylePepperoniPizza();
}
return pizza;
}
ChicagoPizzaStore.java
public class ChicagoPizzaStore extends PizzaStore {
Pizza createPizza(String type) {
Pizza pizza = null;
if("cheese".equals(type)){
pizza = new ChicagoStyleCheesePizza();
}
else if("clam".equals(type)){
pizza = new ChicagoStyleClamPizza();
}
else if("pepperoni".equals(type)) {
pizza = new ChicagoStylePepperoniPizza();
}
else if("veggie".equals(type)){
pizza = new ChicagoStyleVeggiePizza();
}
return pizza;
}
}
做了这么多,应该可以吃披萨了吧。Ethan要一份纽约口味的披萨,Joel须要芝加哥口味的披萨。
PizzaTestDrive.java
public class PizzaTestDrive {
public static void main(String[] args) {
System.out.println("---------Joel 须要的芝加哥的深盘披萨---------");
ChicagoPizzaStore chicagoPizzaStore = new ChicagoPizzaStore(); //建立芝加哥的披萨店
Pizza joelPizza =chicagoPizzaStore.orderPizza("cheese"); //下订单
System.out.println("Joel ordered a " + joelPizza.getName() + "\n");
System.out.println("---------Ethan 须要的纽约风味的披萨---------");
NYPizzaStore nyPizzaStore = new NYPizzaStore();
Pizza ethanPizza = nyPizzaStore.orderPizza("cheese");
System.out.println("Ethan ordered a " + ethanPizza.getName() + "\n");
}
}
运行结果。
六、工厂方法模式的优缺陷
长处
1、 在工厂方法中,用户只须要知道所要产品的详细工厂,无须关系详细的创建过程,甚至不须要详细产品类的类名。
2、 在系统增加新的产品时,我们只须要添加一个详细产品类和对应的实现工厂,无需对原工厂进行任何修改,很好地符合了“开闭准则”。
缺陷
1、 每次增加一个产品时,都须要增加一个详细类和对象实现工厂,是的系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统详细类的依附。这并非什么好事。
七、工厂方法适用场景
1、一个类不知道它所须要的对象的类。在工厂方法模式中,我们不须要详细产品的类名,我们只须要知道创建它的详细工厂即可。
2、一个类通过其子类来指定创建那个对象。在工厂方法模式中,对于抽象工厂类只须要供给一个创建产品的接口,而由其子类来确定详细要创建的对象,在程序运行时,子类对象将覆盖父类对象,从而使得系统更轻易扩展。
3、将创建对象的任务委托给多个工厂子类中的某一个,客户端在应用时可以无须关怀是哪个工厂子类创建产品子类,须要时再动态指定。
七、总结
1、工厂方法模式完整符合“开闭准则”。
2、工厂方法模式应用继承,将对象的创建委托给子类,通过子类实现工厂方法来创建对象。
3、工厂方法答应类将实例化延伸到子类进行。
4、工厂方法让子类决议要实例化的类时哪个。在这里我们要明白这并非工厂来决议生成哪类产品,而是在编写创建者类时,不须要知道实际创建的产品是哪个,选择了应用哪个子类,就已决议了实际创建的产品时哪个了。
5、在工厂方法模式中,创建者通常会包括依附于抽象产品的代码,而这些抽象产品是、由子类创建的,创建者不须要真的知道在制作哪类详细产品。
文章结束给大家分享下程序员的一些笑话语录: IT业众生相
第一级:神人,天资过人而又是技术狂热者同时还拥有过人的商业头脑,高瞻远瞩,技术过人,大器也。如丁磊,求伯君。
第二级:高人,有天赋,技术过人但没有过人的商业头脑,通常此类人不是顶尖黑客就是技术总监之流。
第三级:牛人,技术精湛,熟悉行业知识,敢于创新,有自己的公司和软件产品。
第四级:工头,技术精湛,有领导团队的能力,此类人大公司项目经理居多。
第五级:技术工人,技术精湛,熟悉行业知识但领导能力欠加,此类人大多为系分人员或资深程序员,基本上桀骜不逊,自视清高,不愿于一般技术人员为伍,在论坛上基本以高手面目出现。
第六级:熟练工人,技术有广度无深度,喜欢钻研但浅尝辄止。此类人大多为老程序员,其中一部分喜欢利用工具去查找网上有漏洞的服务器,干点坏事以获取成绩感。如果心情好,在论坛上他们会回答菜鸟的大部分问题。此级别为软件业苦力的重要组成部分。
第七级:工人,某些技术较熟练但缺乏深度和广度,此类人大多为程序员级别,经常在论坛上提问偶尔也回答菜鸟的问题。为软件产业苦力的主要组成部分。
第八级:菜鸟,入门时间不长,在论坛上会反复提问很初级的问题,有一种唐僧的精神。虽然招人烦但基本很可爱。只要认真钻研,一两年后就能升级到上一层。
第九级:大忽悠,利用中国教育的弊病,顶着一顶高学历的帽子,在小公司里混个软件部经理,设计不行,代码不行,只会胡乱支配下属,拍领导马屁,在领导面前胡吹海侃,把自己打扮成技术高手的模样。把勾心斗角的办公室文化引入技术部门,实在龌龊!
第十级:驴或傻X,会写SELECT语句就说自己精通ORALCE,连寄存器有几种都不知道就说自己懂汇编,建议全部送到日本当IT产业工人,挣了日本人的钱还严重打击日本的软件业!
--------------------------------- 原创文章 By
产品和模式
---------------------------------