《Head First 设计模式》:工厂方法模式
正文
一、定义
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
PS:在设计模式中,“实现一个接口”泛指实现某个超类型(可以是类或接口)的某个方法。
要点:
- 通过子类来创建具体的对象。客户只需要知道他们所使用的抽象类型即可。
- 由子类决定要实例化的类是哪一个,是指在编写创建者类时,不需要知道实际创建的产品是哪一个。选择了使用哪个创建者子类,自然就决定了实际创建的产品是什么。
- 对象统一由定义好的工厂方法来创建。
二、实现步骤
1、创建产品抽象类
/**
* 产品抽象类
*/
public abstract class Product {
String name;
public String getName() {
return name;
}
}
2、创建具体的产品,并继承产品抽象类
(1)产品A1
/**
* 产品A1
*/
public class ConcreteProductA1 extends Product {
public ConcreteProductA1() {
name = "ConcreteProductA1";
}
}
(2)产品A2
/**
* 产品A2
*/
public class ConcreteProductA2 extends Product {
public ConcreteProductA2() {
name = "ConcreteProductA2";
}
}
(3)产品B1
/**
* 产品B1
*/
public class ConcreteProductB1 extends Product {
public ConcreteProductB1() {
name = "ConcreteProductB1";
}
}
(4)产品B2
/**
* 产品B2
*/
public class ConcreteProductB2 extends Product {
public ConcreteProductB2() {
name = "ConcreteProductB2";
}
}
3、创建创建者抽象类,并定义用来创建产品的工厂方法
创建者一般为需要用到产品的类,需要的产品则通过类中的工厂方法创建。
/**
* 创建者抽象类
*/
public abstract class Creator {
/**
* 创建产品(工厂方法)
*/
protected abstract Product createProduct(String productType);
}
4、创建具体的创建者,并继承创建者抽象类
具体的创建者需要实现创建产品的工厂方法。
(1)创建者1
/**
* 创建者1
*/
public class ConcreteCreator1 extends Creator {
@Override
protected Product createProduct(String productType) {
// 由具体的创建者(子类)决定创建哪个类的对象
if ("A".equals(productType)) {
return new ConcreteProductA1();
} else if ("B".equals(productType)) {
return new ConcreteProductB1();
}
return null;
}
}
(2)创建者2
/**
* 创建者2
*/
public class ConcreteCreator2 extends Creator {
@Override
protected Product createProduct(String productType) {
// 由具体的创建者(子类)决定创建哪个类的对象
if ("A".equals(productType)) {
return new ConcreteProductA2();
} else if ("B".equals(productType)) {
return new ConcreteProductB2();
}
return null;
}
}
5、创建者通过工厂方法创建产品
public class Test {
public static void main(String[] args) {
// 创建者1
Creator creator1 = new ConcreteCreator1();
// 创建者2
Creator creator2 = new ConcreteCreator2();
// 通过工厂方法创建产品
Product product = creator1.createProduct("A");
System.out.println("创建者1创建产品A:" + product.getName());
product = creator2.createProduct("A");
System.out.println("创建者2创建产品A:" + product.getName());
}
}
三、举个栗子
1、背景
假设你有一个披萨店,出售多种类型的披萨:芝士披萨、蛤蜊披萨、素食披萨等。由于经营有成,你打算推广自己的加盟店。
为了确保加盟店运营的质量,你希望加盟店能够采用固定的制作流程。但是由于区域的差异,每家加盟店都可能想要提供不同风味的披萨(比如纽约、芝加哥、加州),因此又必须允许加盟店能够自由地制作该区域的风味。
2、实现
披萨店子类通过实现创建披萨方法来决定要创建什么风味的披萨。
(1)创建披萨抽象类
/**
* 披萨抽象类
*/
public abstract class Pizza {
/**
* 名称
*/
String name;
/**
* 面团
*/
String dough;
/**
* 酱料
*/
String sauce;
/**
* 佐料
*/
ArrayList<String> toppings = new ArrayList<>();
void prepare() {
System.out.println("Preparing " + name);
System.out.println("Tossing dough...");
System.out.println("Adding souce...");
System.out.println("Adding toppings: ");
for (int i = 0; i < toppings.size(); i++) {
System.out.println(" "+ toppings.get(i));
}
}
/**
* 烘烤
*/
void bake() {
System.out.println("Bake for 25 minutes at 350");
}
/**
* 切片
*/
void cut() {
System.out.println("Cutting the pizza into diagonal slices");
}
/**
* 装盒
*/
void box() {
System.out.println("Place pizza in official PizzaStore box");
}
public String getName() {
return name;
}
}
(2)创建不同风味、不同类型的披萨
/**
* 纽约风味的芝士披萨
*/
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 NYStyleClamPizza extends Pizza {
public NYStyleClamPizza() {
name = "NY Style Sauce Clam Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";
toppings.add("Fresh Clams");
}
}
/**
* 芝加哥风味的芝士披萨
*/
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");
}
void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
/**
* 芝加哥风味的蛤蜊披萨
*/
public class ChicagoStyleClamPizza extends Pizza {
public ChicagoStyleClamPizza() {
name = "Chicago Style Clam Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
toppings.add("Frozen Clams");
}
void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
(3)创建披萨店抽象类
/**
* 披萨店抽象类
*/
public abstract class PizzaStore {
/**
* 订购披萨
*/
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
/**
* 创建披萨(工厂方法)
*/
protected abstract Pizza createPizza(String type);
}
(4)创建不同风味的披萨店
/**
* 纽约风味披萨店
*/
public class NYStylePizzaStore extends
protected Pizza createPizza(String type) {
Pizza pizza = null;
if ("cheese".equals(type)) {
pizza = new NYStyleCheesePizza();
} else if ("clam".equals(type)) {
pizza = new NYStyleClamPizza();
}
return pizza;
}
}
/**
* 芝加哥风味披萨店
*/
public class ChicagoStylePizzaStore extends PizzaStore {
@Override
protected Pizza createPizza(String type) {
Pizza pizza = null;
if ("cheese".equals(type)) {
pizza = new ChicagoStyleCheesePizza();
} else if ("clam".equals(type)) {
pizza = new ChicagoStyleClamPizza();
}
return pizza;
}
}
(5)使用不同风味的披萨店订购披萨
public class Test {
public static void main(String[] args) {
// 纽约风味披萨店
PizzaStore nyStore = new NYStylePizzaStore();
// 芝加哥风味披萨店
PizzaStore chicagoStore = new ChicagoStylePizzaStore();
// 订购芝士披萨
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");
}
}
《Head First 设计模式》:工厂方法模式的更多相关文章
- 《Android源码设计模式》--Builder模式
No1: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 No2: 在Android源码中,最常用到的Builder模式就是AlertDialog.Builder No3: ...
- 《Android源码设计模式》--模板方法模式
No1: 模板方法模式包括:抽象类(其中定义了一系列顺序方法).具体实现类A.具体实现类B 如果子类有实现不一样的细节,重写父类的某个方法即可 No2: AsyncTask对象调用execute方法后 ...
- 《Android源码设计模式》--状态模式--责任链模式--解释器模式--命令模式--观察者模式--备忘录模式--迭代器模式
[状态模式] No1: Wifi设置界面是一个叫做WifiSetting的Fragment实现的 No2: 在不同的状态下对于扫描Wifi这个请求的处理是完全不一样的.在初始状态下扫描请求被直接忽略, ...
- 《Android源码设计模式》--原型模式
No1: 原型模式使用场景: 1)类初始化需要消耗非常多的资源,这个资源包括数据.硬件资源等,通过原型复制避免这些消耗 2)通过new产生一个对象需要非常繁琐的数据准备货访问权限,这是可以使用原型模式 ...
- 《Android源码设计模式》--策略模式
No1: 定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化. No2: 使用场景: 1)针对同一类型问题的多种处理方式,仅 ...
- 《Android源码设计模式》学习笔记之ImageLoader
微信公众号:CodingAndroid cnblog:http://www.cnblogs.com/angel88/ CSDN:http://blog.csdn.net/xinpengfei521 需 ...
- 4. 星际争霸之php设计模式--工厂方法模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- C++设计模式——工厂方法模式
本文版权归果冻说所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.» 本文链接:http://www.jellythink.com/arch ...
- 《Android源码设计模式》--工厂方法模式
No1: 对于一个应用程序来说,其真正的入口是在ActivityThread类中,ActivityThread中含有我们熟悉的main方法.ActivityThread是一个final类,不能被继承. ...
- 《Android源码设计模式》--抽象工厂模式
No1: 4种MediaPlayer Factory分别会生成不同的MediaPlayer基类:StagefrightPlayer.NuPlayerDriver.MidiFile和TestPlayer ...
随机推荐
- C#数据结构与算法系列(十):中缀表达式转后缀表达式
1.具体步骤 1)初始化两个栈:运算符栈s1和储存中间结果的栈s2:2)从左至右扫描中缀表达式:3)遇到操作数时,将其压s2:4)遇到运算符时,比较其与s1栈顶运算符的优先级: (1)如果s1 ...
- Spring AOP学习笔记04:AOP核心实现之创建代理
上文中,我们分析了对所有增强器的获取以及获取匹配的增强器,在本文中我们就来分析一下Spring AOP中另一部分核心逻辑--代理的创建.这部分逻辑的入口是在wrapIfNecessary()方法中紧接 ...
- 工业4.0:换热站最酷设计—— Web SCADA 工业组态软件界面
前言 随着工业4.0的不断普及与发展,以及国民经济的飞速前进,我国的城市集中供热规模也不断扩大,科学的管理热力管网具有非常重大的经济和社会效益.目前热力系统,如换热站大都采用人工监控,人工监控不仅浪费 ...
- IDEA SonarLint安装及使用
SonarLint插件安装IDEA菜单栏选择File->Settings,左边栏选择Plugins 在线安装选择Browse repositories,搜索Sonar,选择SonarLint进行 ...
- Python3-logging模块-日志记录
Python3中的logging模块提供了较为灵活的事件日志系统 日志级别 DEBUG < INFO < WARING(Python默认) < ERROR < FATAL(CR ...
- 解决UEditor编辑时,只添加视频内容,不添加文字,视频信息不能保存到数据库的问题
造成这个问题的原因是富文本保存内容时会筛除空标签,然后统计是否有内容,通过字数统计也可以看到,上传完视频后字数还是零,因为视频上传后是<video></video>标签,这个标 ...
- spring引用hibernate映射文件的四种方式
1.mappingResources 2.mappingLocations 3.mappingDirectoryLocations 4.mappingJarLocations 四种方式:https:/ ...
- SpringCloud之zuul
- node解压压缩包以及压缩图片
node解压压缩包以及压缩图片 首先保证电脑安装node环境,下载地址:http://nodejs.cn //可以打开一个dos窗口输入node -v进行确认是否安装成功 C:\ > node ...
- Java基础-线程与并发1
线程与并发 Thread 基本概念 程序: 一组计算机能识别和执行的指令 ,是静态的代码. 进程: 程序的一次运行活动, 运行中的程序 . 线程: 进程的组成部分,它代表了一条顺序的执行流. 进程线程 ...