Head First设计模式(阅读笔记)-04.工厂模式
创始人
2024-02-16 19:04:37

披萨订购

假设要完成披萨订购的功能,披萨的种类很多,比如 GreekPizzCheesePizz 等,披萨店会根据用户需要的披萨种类制作披萨,制作的流程包括prepare->bake->cut->box


简单实现

下面代码的实现十分简单清晰,但是如果披萨类型增加或删除,需要去修改代码,不符合开闭原则(类应该对扩展开发,对修改关闭)


// 下面不同的pizza类型都继承了相同的父类
Pizza orderPizza(String type){Pizza pizza;if(type.equals("cheese")){pizza = new CheesePizza();}else if(type.equals("clam")){pizza = new ClamPizza();}pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;
}

工厂模式


简单的披萨工厂-简单工厂模式

从上述代码可以看出,出了创建披萨对象的代码需要修改,其他代码都是不变的,所以可以将创建披萨对象的代码分离出来作为一个新对象-披萨工厂:

  • 此时orderPizza方法变为该工厂的客户,它无需知道工厂如何得到一个披萨,只关心从工厂可以得到一个披萨,并且可以调用方法对披萨进行准备、烘烤等操作
  • 并且该工厂可以有许多客户,比如制作披萨点的菜单就可以利用该工厂制作的披萨来制定价钱等

// 简单披萨工厂
public class SimplePizzaFactory{public Pizza createPizza(String type){Pizza pizza = null;if(type.equals("cheese")){pizza = new CheesePizza();}else if(type.equals("clam")){pizza = new ClamPizza();}return pizza;}
}
public class PizzaStore{SimplePizzaFactory factory;// 披萨店需要指定一个工厂public PizzaStore(SimplePizzaFactory factory){this.factory = factory;}public Pizza orderPizza(String type){Pizza pizza;factory.createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;
}

加盟披萨店-工厂方法模式

此时在纽约等地区想在当地加盟该披萨店,并且希望工厂能加工出纽约风味的披萨


给每个地区创建一个工厂

下面代码的缺陷在于无法让各地区的加盟店决定自己的制作流程,只是决定采用哪个工厂而已

NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.orderPizza("Veggie");  // 在纽约工厂制作的纽约风味披萨
让加盟店自己决定制作流程

原本由一个对象负责所有具体类的实例化,现在通过子类负责实例化


public abstract class PizzaStore{// orderPizza可以声明为final,防止被子类覆盖public Pizza orderPizza(String type){Pizza pizza;pizza = createPizza(type)  // 从createPizza方法从工厂中移到披萨店中pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}// 定义为抽象,必须实现protected abstract Pizza createPizza(String type);
}public class NYPizzaStrore extends PizzaStore{// 子类全权负责实例化哪个具体Pizza,父类并不知道具体创建的披萨是哪一种,只知道这个披萨要进行烘烤、切片等流程Pizza createPizza(String item){if(item.equals("chess")){return new NYStyleCheesePizza();}else if(...){...}}
}// 定义一个抽象的披萨类
public abstract class Pizza{String name;void cut(){System.out.println("切成方块");}
}// 纽约风味的披萨
public class NYStyleCheesePizza extends Pizza{public NYStyleCheesePizza(){name = "NYStyle with cheese"}void cut(){System.out.println("切成三角形");}
}// 测试
public class Test{public static void main(String[] agrs){PizzaStore nyStore = new NYPizzaStrore();Pizza pizza = nyStore.orderPizza("cheese");  // nyStore决定要制作什么披萨}
}
工厂方法模式

定义了一个创建对象的接口,由子类决定要实例化哪个类


在这里插入图片描述

依赖倒置原则

对于工厂方法模式还依赖了一个原则-依赖倒置原则,该原则表示要依赖抽象,不要依赖具体类,换个说法就是高层组件和低层组件都应该依赖于抽象


在这里插入图片描述

使用当地原材料-抽象工厂模式

假设不同地区的加盟店制作披萨要求用当地的原材料制作


创建当前原料工厂

很明显可以想到,不可能只存在一家工厂生产不同地区需要的原料,然后空运过去,可以在当地创建一个原料工厂


// 抽象原料工厂
public interface PizzaIngredientFactory{public Sauce createSauce();public Cheese createCheese();
}
// 纽约的原料工厂
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{public Sauce createSauce(){return new NYSauce();  // 使用当前材料}...
}
重新制作披萨

// 抽象披萨类,将prepare方法定义为抽象了
public abstract class Pizza{String name;Sauce sauce;Cheese Cheese;// 声明为抽象是因为现在当地披萨需要使用自己的原材料进行准备abstract void prepare();void cut(){System.out.println("切成方块");}
}
// 现在根据使用不同的原料工厂就可以区分出是哪个地区的CheesePizza了
public class CheesePizza extends Pizza{PizzaIngredientFactory ingredientFactory;// 只需要传入需要地区的原料工厂即可public CheesePizza(PizzaIngredientFactory ingredientFactory){this.ingredientFactory = ingredientFactory;}void prepare(){// 通过传入的原料工厂就可以生产出该工程的saucesauce = ingredientFactory.createSauce();...}
}public class NYPizzaStore extends PizzaStore{Pizza createPizza(String item){Pizza pizza = null;// 纽约加盟店肯定使用纽约原料工厂了PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();if(item.equals("chess")){// 现在不需要写为NYStyleCheesePizza,只需要传入对于原料工厂即可pizza = new CheesePizza(ingredientFactory);}else if(...){...}return pizza;}
}// 测试(代码没有变化)
public class Test{public static void main(String[] agrs){PizzaStore nyStore = new NYPizzaStrore();Pizza pizza = nyStore.orderPizza("cheese");}
}
抽象工厂模式

提供一个接口用于创建相关或依赖对象的家族,并且不需要明确具体类(比如在NYPizzaStorecreatePizza方法中,并没有明确具体的NYStyleCheesePizza,而是传入一个原料工厂)


参考

Head First 设计模式-工厂模式

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...