3.java设计模式之工厂模式
基本需求:
- 一个披萨店需要订购不同种类的披萨
传统方式:
实现思路
- 在订购类中根据用户不同的输入直接创建不同的披萨实体类进行返回
UML类图
代码实现
披萨类
// 抽象父类
public abstract class Pizza { String name; public abstract void prepare(); public void bake() {
System.out.println(this.name + "披萨烘焙中");
} public void cut() {
System.out.println(this.name + "披萨切割中");
} public void box() {
System.out.println(this.name + "披萨打包中");
} } // 奶酪披萨 子类1
public class CheesePizza extends Pizza { public CheesePizza(String name) {
this.name = name;
} @Override
public void prepare() {
System.out.println(this.name + "披萨准备原材料中");
} }
// 希腊披萨 子类2
public class GreekPizza extends Pizza{ public GreekPizza(String name) {
this.name = name;
} @Override
public void prepare() {
System.out.println(this.name + "披萨准备原材料中");
} }
订购类
public class PizzaStore { public static void main(String[] args) {
new PizzaStore().OrderPizza();
} // 订购披萨方法 传统方式直接采用new出子类的方法进行返回对应的披萨
public void OrderPizza() {
Pizza pizza;
Scanner scanner = new Scanner(System.in);
String orderType;
while (true) {
System.out.println("输入披萨的种类:");
orderType = scanner.nextLine();
if (StringUtils.equals("cheese", orderType)) {
pizza = new CheesePizza("cheese");
} else if (StringUtils.equals("greek", orderType)) {
pizza = new GreekPizza("greek");
} else {
System.out.println("没有该类型的披萨");
break;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
} }
缺陷及改进:
- 在订购方法中,直接采用new出子类的方法进行返回对应的披萨,违反了设计模式的ocp原则,即对扩展开放,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码
- 如果新增加一种类型的披萨,则需要修改OrderPizza的方法实现,如果有多个创建Pizza的方法则都需要修改
- 把创建Pizza对象封装到一个类中,这样我们有新的Pizza种类时,只需要修改该类就可,其它有创建Pizza对象的代码就不需要修改了——>简单工厂模式
简单工厂模式:
简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式
实现思路
- 创建一个简单工厂类SimpleFactory,提供一个创建Pizza的方法,PizzaStore想要Pizza时,直接在工厂中获取即可
UML类图
代码实现
// 简单工厂类 Pizza类及实现类同上
public class SimpleFactory { // 创建Pizza的方法 可在多个地方调用,如果需要增加其他种类的Pizza则只需要修改此方法内部的实现即可,不需要调用方
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if (StringUtils.equals("cheese", orderType)) {
pizza = new CheesePizza("cheese");
} else if (StringUtils.equals("greek", orderType)) {
pizza = new GreekPizza("greek");
} else {
System.out.println("没有该类型的披萨");
}
return pizza;
} // 简单工厂也叫静态工厂 可直接提供静态的方法获取对象
public static Pizza createPizza1(String orderType) {
Pizza pizza = null;
if (StringUtils.equals("cheese", orderType)) {
pizza = new CheesePizza("cheese");
} else if (StringUtils.equals("greek", orderType)) {
pizza = new GreekPizza("greek");
} else {
System.out.println("没有该类型的披萨");
}
return pizza;
} }
public class PizzaStore { public static void main(String[] args) {
// new PizzaStore().OrderPizza();
new PizzaStore(new SimpleFactory());
} private SimpleFactory simpleFactory; public PizzaStore(SimpleFactory simpleFactory) {
this.simpleFactory = simpleFactory;
OrderPizza();
} private void OrderPizza() {
Pizza pizza;
Scanner scanner = new Scanner(System.in);
String orderType;
while (true) {
System.out.println("输入披萨的种类:");
orderType = scanner.nextLine();
// 通过Pizza工厂获取Pizza对象
pizza = simpleFactory.createPizza(orderType);
if (null == pizza) {
break;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
} }
工厂方法模式:
在上面的基础上增加了新的需求,需要在每种pizza上加上产地,例如 北京的奶酪pizza、北京的胡椒pizza或者是伦敦的奶酪pizza、伦敦的胡椒pizza
思路1:可以使用简单工厂模式,新建两个简单工厂,BJPizzaSimpleFactory和LDPizzaSimpleFactory 但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好
思路2:采用工厂方法模式
- 将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现
- 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
实现思路
- 在PizzaStore中增加一个创建Pizza抽象方法,由BJPizzaStore和LDPizzaStore去实现,至此该两个子类创建的Pizza都是各自地区的
UML类图
代码实现
// 含有抽象方法的抽象类
public abstract class PizzaStore { public static void main(String[] args) {
// 根据地区选工厂? 没品出来和创建多个简单工厂有什么好处
String area = "BJ";
if (area.equals("BJ")) {
new BJPizzaStore();
} else {
new LDPizzaStore();
}
} public PizzaStore() {
OrderPizza();
} private void OrderPizza() {
Pizza pizza;
Scanner scanner = new Scanner(System.in);
String orderType;
while (true) {
System.out.println("输入披萨的种类:");
orderType = scanner.nextLine();
// 使用抽象方法来创建Pizza,使用不同的实现类将会得到不同的披萨
pizza = createPizza(orderType);
if (null == pizza) {
break;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
} // 创建Pizza的抽象方法 由子类实现
public abstract Pizza createPizza(String orderType); }
// 子类1
public class BJPizzaStore extends PizzaStore { @Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if (StringUtils.equals("cheese", orderType)) {
pizza = new BJCheesePizza("BJCheese");
} else if (StringUtils.equals("pepper", orderType)) {
pizza = new BJPepperPizza("BJPepper");
} else {
System.out.println("没有该类型的披萨");
}
return pizza;
}
} // 子类2
public class LDPizzaStore extends PizzaStore { @Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if (StringUtils.equals("cheese", orderType)) {
pizza = new BJCheesePizza("LDCheese");
} else if (StringUtils.equals("pepper", orderType)) {
pizza = new BJPepperPizza("LDPepper");
} else {
System.out.println("没有该类型的披萨");
}
return pizza;
}
}
抽象工厂模式:
抽象工厂模式定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类,可以将简单工厂模式和工厂方法模式进行整合
从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象),将工厂抽象成两层,
实现思路
- 创建AbsFactory( 抽象工厂) 和具体实现的工厂子类,使用时创建工厂子类即可
UML类图
代码实现
// 抽象工厂类
public interface AbsFactory { Pizza createPizza(String orderType); } // 子类1
public class BJFactory implements AbsFactory { @Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if (StringUtils.equals("cheese", orderType)) {
pizza = new BJCheesePizza("BJCheese");
} else if (StringUtils.equals("pepper", orderType)) {
pizza = new BJPepperPizza("BJPepper");
} else {
System.out.println("没有该类型的披萨");
}
return pizza;
} } // 子类2
public class LDFactory implements AbsFactory { @Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if (StringUtils.equals("cheese", orderType)) {
pizza = new BJCheesePizza("LDCheese");
} else if (StringUtils.equals("pepper", orderType)) {
pizza = new BJPepperPizza("LDPepper");
} else {
System.out.println("没有该类型的披萨");
}
return pizza;
} }
public class PizzaStore { public static void main(String[] args) {
new PizzaStore(new BJFactory());
} private AbsFactory factory; public PizzaStore(AbsFactory factory) {
// 在此处声明需要工厂类对象 , 使用时直接创建抽象工厂的子类对象即可
this.factory = factory;
OrderPizza();
} private void OrderPizza() {
Pizza pizza;
Scanner scanner = new Scanner(System.in);
String orderType;
while (true) {
System.out.println("输入披萨的种类:");
orderType = scanner.nextLine();
// 使用抽象方法来创建Pizza,使用不同的实现类将会得到不同的披萨
pizza = factory.createPizza(orderType);
if (null == pizza) {
break;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
} }
jdk源码:
在Calendar类中的getInstance()方法中有用到简单工厂模式
public static Calendar getInstance()
{
// 获取默认的zone和aLocale
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
} public static Calendar getInstance(TimeZone zone,
Locale aLocale)
{
return createCalendar(zone, aLocale);
} private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
CalendarProvider provider =
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
.getCalendarProvider();
if (provider != null) {
try {
return provider.getInstance(zone, aLocale);
} catch (IllegalArgumentException iae) {
// fall back to the default instantiation
}
} Calendar cal = null;
// 此处使用了简单工厂模式来创建Calender对象 通过aLocale不同的后缀
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
} ...... return cal;
}
注意事项:
- 意义:将实例化对象的的代码抽取出来,放到一个类中同一管理和维护,在项目中达到依赖解耦的目的,提高项目的扩展性和维护性
- 依赖抽象原则(尽量依赖抽象的东西)
- 创建对象时,不要使用new,而是将new的东西放在一个工厂中并返回
- 不要让类继承一个具体的类,而是继承抽象类或者实现接口,不要覆盖基类汇总已经实现的方法
3.java设计模式之工厂模式的更多相关文章
- 浅析JAVA设计模式之工厂模式(一)
1 工厂模式简单介绍 工厂模式的定义:简单地说,用来实例化对象,取代new操作. 工厂模式专门负责将大量有共同接口的类实例化.工作模式能够动态决定将哪一个类实例化.不用先知道每次要实例化哪一个类. 工 ...
- Java设计模式之工厂模式(Factory模式)介绍(转载)
原文见:http://www.jb51.net/article/62068.htm 这篇文章主要介绍了Java设计模式之工厂模式(Factory模式)介绍,本文讲解了为何使用工厂模式.工厂方法.抽象工 ...
- Java 设计模式之工厂模式(二)
原文地址:Java 设计模式之工厂模式(二) 博客地址:http://www.extlight.com 一.背景 本篇内容是 Java 设计模式创建型模式的第二篇.上一篇主题为 <Java 设计 ...
- 浅析JAVA设计模式之工厂模式(二)
1 工厂方法模式简单介绍 工厂方法 (Factroy Method)模式:又称多态性工厂模式(Polymorphic Factory),在这样的模式中,核心工厂不再是一个详细的类.而是一个抽象工厂,提 ...
- java设计模式2————工厂模式
1.工厂模式介绍: 1.1.实现了创建者与调用者的分离 1.2.详细分类: 简单工厂模式 工厂方法模式 抽象工厂模式 1.3.所遵循的OOP原则: 开闭原则:对扩展开放,对修改关闭 依赖倒转原则:面向 ...
- java 设计模式之工厂模式与反射的结合
工厂模式: /** * @author Rollen-Holt 设计模式之 工厂模式 */ interface fruit{ public abstract void eat(); } ...
- JAVA设计模式--抽象工厂模式
抽象工厂设计模式 1.系统中有多个产品族,而系统一次只可能消费其中一族产品2.同属于同一个产品族的产品以其使用.来看看抽象工厂模式的各个角色(和工厂方法的如出一辙):抽象工厂角色: 这是工厂方法模式的 ...
- Java设计模式之-----工厂模式(简单工厂,抽象工厂)
一.工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式在<Java与模式>中分为三类:1)简单工厂模式(Simple Factor ...
- Java设计模式之工厂模式(简单工厂模式+工厂方法模式)
摘自http://blog.csdn.net/jason0539/article/details/23020989 在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是 ...
- java设计模式之一工厂模式
简单工厂模式是java设计模式中最简单的设计模式之一: 工厂模式是最常用的设计模式之一. 工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模 ...
随机推荐
- centos7 yum 安装nodejs、npm、cnpm、pm2、yarn
一.环境准备 1.1 查看系统环境 [root@localhost ~]# cat /etc/redhat-release CentOS Linux release 7.5.1804 (Core) [ ...
- shell-变量输入内置read命令详解
1. shell变量的输入 shell变量除了可以直接赋值或脚本传参外,还可以使用read命令从标准输入得. [语法格式] read [参数] [变量名] [常用参数] -p:指定读取值时的提示符: ...
- 多台centos7服务器实现SSH免密登陆
一.环境 centos7.x 三台 node1.node2.node3 二.实现免密登陆 2.1.node1上,生成公钥与私钥 [root@node1 ~]# ssh-keygen Generatin ...
- 1.Linux内核模块编程
1.模块加载程序结构 - 模块加载函数: static int _init init_function(void); module_init(init_function); - 模块卸载函数: sta ...
- 多测师讲解第一个月 _综合面试题_高级讲师肖sir
第一个月综合面试题 1. 冒烟测试是什么意思? 对主要的用例测试 2.你们公司的项目流程是什么? 3.你们公司的bug分几个级别? 4个 4.你对外键是怎么理解的? 你会使用外键吗?给一个表添加 ...
- pytest文档44-allure.dynamic动态生成用例标题
前言 pytest 结合 allure 描述用例的时候我们一般使用 @allure.title 和 @allure.description 描述测试用例的标题和详情. 在用例里面也可以动态更新标题和详 ...
- 编程福利:50本C语言电子书,你还怕没书看吗!
推荐适合编程新手入门的几本经典的C语言书籍. 1.<C程序设计语言> C语言之父的著作,被称为C语言的的圣经.全球最经典的C语言教程.这本书最大的特点是精炼.读起来不会觉得"啰嗦 ...
- 【UR #13】Yist
UOJ小清新题表 题目摘要 UOJ链接 给出一个排列 \(A\) 以及它的一个非空子序列 \(B\),给出一个 \(x\) 并进行若干次操作,每一次操作需要在 \(A\) 中选择一个长度恰好为 \(x ...
- kubernetes:用label让pod在指定的node上运行(kubernetes1.18.3)
一,为什么要为node指定label? 通常scheduler会把pod调度到所有可用的Node,有的情况下我们希望能把 Pod 部署到指定的 Node, 例如: 有的Node上配备了速度更快的SSD ...
- java: 非法字符: '\ufeff'
错误问题记录: Error:(1, 1) java: 非法字符: '\ufeff' Error:(1, 1) 错误: 需要class, interface或enum报错 问题发生时因为编码问题导致,如 ...



