明亮解我“工厂模式无用”之惑
明亮,是我的大学同学,我们一个在北京,一个在深圳,昨晚两人视频关于工厂模式聊到深夜。
明亮啊,我怎么觉得工厂模式没有用啊!
不会啊,工厂模式可是最常用的设计模式之一,你说说为啥觉得没用。
你看我给你举个例子,就以餐馆为例吧,类图如下所示,其中 FoodFactory、Food 是抽象类。
首先,如果餐馆的 cook() 通过工厂模式来创建 Food,代码如下:
public class Restaurant {
public Food cook() {
FoodFactory factory = new ChineseFoodFactory();
Food food = factory.createFood();
return food;
}
}
而如果不使用工厂模式,代码如下:
public class Restaurant {
public Food cook() {
Food food = new ChineseFood();
return food;
}
}
如果我们使用工厂模式,可以不需要知道具体创建的 Food 类,但是仍需知道具体的 Factory 类,也都要 new 一个对象出来,工厂类只是把 new Food 的逻辑封装了下,并没起到什么作用啊,而且代码还更复杂了,你说工厂模式是不是没有用?
嗯,确实如你所说,使用工厂模式会让代码变得更加复杂,这是因为我们在原有逻辑上抽象出了一个新的层次概念,但是工厂模式并不是没有用的。你之所以还没能看到工厂模式的好,是因为你还没碰到实例化的具体类容易变化的场景,而在这种场景下,工厂模式能让 Restaurant 类遵循“开放-关闭原则”。而遵循该原则的好处就是,在不修改现有代码的前提下,去搭配新的行为,让我们的代码能弹性地应对变化。
开放-关闭原则:类对扩展开放,对修改关闭。
下面给你举个变化的例子吧,例如,餐馆有一天想尝试做川菜版的中餐,在不使用工厂模式时,我们必须要去修改 Restaurant 的 cook() 方法。
Food food = new ChuangChineseFood();
这样是违背”修改关闭“的。而工厂模式可将实例化具体类的逻辑抽离到工厂中,当面对变化时,通过修改工厂的内部逻辑,来实现 Restaurant 的”修改关闭“。除此之外,工厂模式,通过抽象出工厂接口,让我们能可以实现 Restaurant 的“扩展开放”。我们先对 Restaurant 修改下,把 factory 由局部变量变为成员变量。这样,你便可以利用多态的机制,在运行时传入不同的 Factory 来烹饪食物。
public class Restaurant {
private FoodFactory factory;
public Food cook() {
Food food = factory.createFood();
return food;
}
public void setFoodFactory(FoodFactory factory) {
this.factory = factory;
}
}
例如,当你想白天中餐,晚上做西餐时,只需通过 setter 方法修改 facotry 即可。
if (time == DAY) {
restaurant.setFoodFactory(chineseFoodFactory);
} else {
restaurant.setFoodFactory(westernFoodFactory);
}
Food food = resuaurant.cook();
嗯,明亮,我明白你的意思了,工厂模式虽然麻烦了些,但是能让类遵循“开放-关闭原则”,从而更弹性地去应对改变。原来它这么有用,那以后所有的实例化操作我都使用工厂模式,让我的代码具有超强的弹性,弹~弹~弹~
别逗了,万万不可,并不是所有地方都要使用,只有当实例化具体类容易变化时,使用工厂模式才是合适的,才需要考虑进一步的抽象。而对于不容易变化的实例化操作,是不需要遵循“开放-关闭原则”的,不然就是过度设计了。而如何判断实例化操作是否容易变化,这就需要我们的经验了。
过度设计啊,真有种装X失败的感觉。
哈哈哈,你现在知道工厂模式并非无用了吧。别再小瞧设计模式了,这可都是前人总结的宝贵经验!
禅定时刻
我之前不能理解工厂模式的用处,主要还是自己对工厂模式所需解决的问题不清楚。只有应对实例化具体类容易改变的代码时,工厂模式才能发挥出它真正的本领。大家也要避免过度设计,避免装X失败。
- 小程序让交通出行变得如此简化,看看这些微信小程序你有在用了吗?
- 中小企业如何选择DDoS防御方案?
- “熊医生”出诊正确率超九成 医院:人工智能更多是辅助
- PLC编程优化方法,让程序运行提速!
- 这是硅谷狂人马斯克对未来做出的11个大胆预测,人工智能比核武器更危险
- 在腾讯云上使用自建DNS
- Spring 4.0.2 学习笔记(1) - 最基本的注入
- 关于女神SQLite的疑惑(2)
- WordPress纯代码仿无觅相关文章图文模式功能(增强版)
- 人工智能时代已悄然来临……
- 人民日报发布周鸿祎署名文章:迎接“大安全”时代的新威胁
- Mono 3.2 上跑NUnit测试
- 为WordPress 文章中的链接自动添加 nofollow标签
- 腾讯刘炽平:海外用户破7000万 微信带开发者“出海”
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- MySQL复杂where条件分析
- 超链接标签
- 【剑指Offer】二叉树的镜像
- 【redis6.0.6】redis源码慢慢学,慢慢看 -- 第四天:提纲掣领main函数(server)
- redis学习(六)
- 原生JS实现一个Ajax跨域请求
- 深入理解类加载机制:拨开迷雾见真章
- 修复postgres安装错误 Problem running post-install step. Installation may not complete correctly The datab
- automagica 调用windows画图以及登录qq
- 数据库PostrageSQL-高级特性
- 数据库PostgreSQL-安装
- CentOS 7 安装 PHP 7.4.0 正式版
- ABAP实现设计模式里的观察者-发布者模式
- 如何在SAP S/4HANA里创建自定义的partner function
- Rust 往事 | Loop 和 While True 之争