创建型模式:工厂方法
个人博客原文 创建型模式:工厂方法
简介
姓名:工厂方法
英文名:Factory method Pattern
价值观:扩展是我的专属
个人介绍:
Define an interface for creating an object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses. (定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。) (来自《设计模式之禅》)
你要的故事
还记得上一篇 单例模式 中的故事么?小明开着汽车去旅游、去学校、去聚会。这一次还是延续小明的故事,一个故事能讲 2 个设计模式,不容易呀。。。(每次想故事都想破脑袋,每一篇文章至少有 3 个故事从脑子里闪过,但最终留下的只有一个适合,为了就是能比较清晰简单的说明设计模式中的关键要点。)
简单工厂
小明家里以前不算很富裕,但是还是有一个不错的车库,什么汽车、摩托车、自行车啥的都放在这个车库里。小明每次要出去,都会到车库里面挑合适的车出发。比如,小明最近期末考试了,骑摩托车去学校考试,考完试之后,小明就准备去旅游,这次决定自驾游,开着自己家的小汽车去。这个场景我们用代码描述下。
public class SimpleFactoryTest { public static void main(String[] args) { XiaoMing xiaoMing = new XiaoMing(); // 小明骑摩托车去学校 IVehicle motorcycle = GarageFactory.getVehicle("motorcycle"); xiaoMing.goToSchool(motorcycle); // 小明开汽车去旅游 IVehicle car = GarageFactory.getVehicle("car"); xiaoMing.travel(car); } } /** * 车库 */ class GarageFactory { public static IVehicle getVehicle(String type) { if ("car".equals(type)) { return new Car(); } else if ("motorcycle".equals(type)) { return new Motorcycle(); } throw new IllegalArgumentException("请输入车类型"); } } /** * 交通工具 */ interface IVehicle { void run(); } /** * 汽车 */ class Car implements IVehicle { @Override public void run() { System.out.println("开汽车去。。。。"); } } /** * 摩托车 */ class Motorcycle implements IVehicle { @Override public void run() { System.out.println("骑摩托车去。。。。"); } } class XiaoMing { public void goToSchool(IVehicle vehicle) { System.out.println("小明去学校"); vehicle.run(); } public void travel(IVehicle vehicle) { System.out.println("小明去旅游"); vehicle.run(); } }
上面代码看懂了么? 小明家里有一个车库 GarageFactory,里面放着汽车 Car 和摩托车 Motorcycle,小明要出去的时候,就到车库选择车,通过传递参数给 GarageFactory.getVehicle(),指明要什么车,然后小明就骑着车出发了。
这个代码真正的术语叫:简单工厂模式(Simple Factory Pattern),也叫做静态工厂模式。它是工厂方法中的一个实现方式,从字面理解就可以知道,它是最简单的工厂方法实现方式。它有一点点小缺陷,就是扩展性不够好,在上面代码中,小明只能骑摩托车或者开汽车,如果小明要骑单车出去呢?势必得在 GarageFactory 中添加 if 是自行车的逻辑。这违反了哪条规则了?是不是那个允许扩展,拒绝修改的开闭原则?
不是说简单工厂这种实现方式不好,而是扩展性不够,在平时的开发中,简单工厂模式也用得不少。在这个小明家里车不多的情况下,用一个车库也是合适的。
工厂方法
小明老爸近几年赚了不少,车迷的两父子一直买车,家里的车越来越多,这时候,他们决定多建几个车库,按车类型放置。比如,有一个汽车库,一个摩托车库。这时候小明要开汽车就去汽车库,要骑摩托车就去摩托车库。代码实现如下。
public class FactoryMethodTest { public static void main(String[] args) { XiaoMing xiaoMing = new XiaoMing(); // 小明骑摩托车去学校 VehicleGarage motorcycleGarage = new MotorcycleGarage(); IVehicle motorcycle = motorcycleGarage.getVehicle(); xiaoMing.goToSchool(motorcycle); // 小明开汽车去旅游 VehicleGarage carGarage = new CarGarage(); IVehicle car = carGarage.getVehicle(); xiaoMing.travel(car); } } interface VehicleGarage { IVehicle getVehicle(); } /** * 汽车车库 */ class CarGarage implements VehicleGarage { @Override public IVehicle getVehicle() { return new Car(); } } /** * 摩托车车库 */ class MotorcycleGarage implements VehicleGarage { @Override public IVehicle getVehicle() { return new Motorcycle(); } }
上面代码重用了简单工厂实现方式的交通接口以及摩托车和汽车的实现类。代码中有 2 个车库,一个是汽车车库 CarGarage,一个是摩托车库 MotorcycleGarage。如果小明要骑自行车,只需要建一个自行车车库,完全不用去修改汽车车库或者摩托车车库,就非常符合开闭原则,扩展性大大的提高。
总结
工厂方法模式可以说在你能想到的开源框架源码中必定会使用的一个设计模式,因为开源框架很重要一点就是要有扩展性,而工厂方法模式恰恰具有可扩展性。弄懂了工厂方法模式,以后看开源代码就很得心应手啦。
参考资料:《大话设计模式》、《Java设计模式》、《设计模式之禅》、《研磨设计模式》、《Head First 设计模式》
希望文章对您有所帮助,设计模式系列会持续更新,感兴趣的同学可以关注公众号 LieBrother,第一时间获取文章推送阅读,也可以一起交流,交个朋友。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
开源一个千万级多组Raft库 - Dragonboat
向大家介绍Dragonboat,一个开源的Go实现的多组Raft库,项目已Apache2协议下开源。欢迎大家试用,也请大家点star鼓励:https://github.com/lni/dragonboat 通俗的讲,这是一个分布式共识协议库,应用可以用它把数据分布存储于多台机器上,只要过半数的机器在线,数据与服务便可在线。这避免了因个别机器当机或网络故障而造成数据、服务不可用,提高系统可用性。它提供称为Linearizability的强一致特性:多个副本的数据在外部看来更像使用单一副本,不会有仅提供最终一致性的系统常见且难缠的读到旧版数据的问题。 基于Raft协议的共识库已经应用于很多互联网后台系统。接触了很多用户以后,普遍反馈的当前应用障碍是缺乏一个可靠、高性能、且对共识协议本身接近全透明的开箱即用的通用实现。 优势 Dragonboat已经较好的解决所有上述应用障碍: 测试最完备的开源Raft库之一,所有的实现代码、测试工具、测试结果均已开源。 吞吐性能最好的开源Raft库,千万级每秒实现,平均单核即达每秒40万次以上写吞吐。 功能最完备的开源Raft库,不做特殊应用假设限制,安全...
- 下一篇
如何维护一个自己的 golang doc 服务
本文内容是如何维护一个golang 在线的doc 服务。 1 什么是godoc ? godoc 是 golang 官方提供的文档生成工具, 2 为什么要有godoc ? 我们经常遇到一个问题,就是代码和文档不一致,线上代码版本总和wiki 给的不一样,让人吐槽。为了解决这个痛点问题,golang 给出了个官方方案,也就是,文档应该与代码一起,当更新代码的时候,文档也能够同步得到更新。对于程序员来说,代码发布后,我们文档自动同步更新,这样非常完美。这就是为什么要有 godoc。 3 怎么写godoc ? godoc 支持 package、const、var和 func 这些类型根据注释生成文档,而且只会对公有变量(首字母大写)生成。我们可以直接通过doc 查具体函数签名,函数使用说明,还有example 示例代码。 3.1 package, type, const, func type, const, func以名称为注释的开头, package以Package name为注释的开头, 其中有效的关键字注释不应该超过3行。 // Package AAA ... package AAA /...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- MySQL8.0.19开启GTID主从同步CentOS8
- Red5直播服务器,属于Java语言的直播服务器
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Hadoop3单机部署,实现最简伪集群
- CentOS8编译安装MySQL8.0.19
- CentOS7,8上快速安装Gitea,搭建Git服务器