概述

在程序中创建对象,并设置对象的属性,是我们长干的事儿。当创建对象需要大量的重复代码时,代码看起来就不那么优雅了。从类的职责角度出发,业务类既要实现一定的逻辑,还要负责对象的创建,业务类干的事儿也忒多了点。对象创建也是“一件事”,我们可以将“这件事”从业务代码中提取出来,让专门的类去做“这件事”,这个专门的类一般是“工厂类”,这样使得业务类和工厂类各司其职,代码整洁性得以提高。这就是本文要讲的主题——提取工厂类。

工厂举例

什么都做的PC厂商

某PC厂商生产一系列的笔记本电脑,如果笔记本电脑的各个部件都由PC厂商自己生产提供,没准第一批笔记本电脑还未生产出来,这家PC厂商就已经倒闭了。因为它需要自己研发设计CPU、显卡、内存、硬盘等核心硬件,这些硬件都需要不同的团队来支持,维持并管理好这些团队是非常耗时耗力的。

我们把“类”看作是这个“PC厂商”,所有硬件都靠PC厂商自己研发,意味着类的职责特别多,职责过多也意味着这个类的稳健性较差。
即使这家PC厂商除了CPU,其他所有零件它都生产好了,它仍然不能生产出一台可以正常运行的PC。

专一的PC厂商

那么怎么做会比较合适呢?这个PC厂商找好自己在市场上的定位,树立起这些笔记本的品牌,准备好售前售后策略,至于CPU、显卡、内存、硬盘这些核心硬件,联络优质的厂家,由他们来供货。然后,拿着这些厂家提供的硬件,在自己的工厂里生产组装笔记本电脑,贴上自己的品牌,最终推向市场。
这样做的好处是,PC的各个零件不需要自己的团队来研发,也不需要自己生产,他们负责联络合适的供应商,由供应商生产这些硬件,他们只需专注于品牌设计、PC组装和市场推广这些环节,这也使得他们的整体风险降低了。

这个过程中包含三方:Client(PC厂商)、Factory(硬件厂商)和Product(硬件产品),可以用下面的图来表示。

站在硬件厂商的角度,PC厂商是他们的客户,硬件厂商为PC厂商提供PC零件。

注意:这个示例中的“专一”是指PC厂商专注于品牌设计、PC组装和市场推广。

示例

重构前

PoliceCarController类的New()方法包含了创建PoliceCar的所有逻辑

public class PoliceCarController
{public PoliceCar New(int mileage, bool serviceRequired){PoliceCar policeCar = new PoliceCar();policeCar.ServiceRequired = serviceRequired;policeCar.Mileage = mileage;return policeCar;}
}public class PoliceCar
{public bool ServiceRequired { get; set; }public int Mileage { get; set; }
}

如果PoliceCar的属性很多,New()方法将变得非常大,代码的可读性和维护性也会降低。从“类的职责”角度去看,PoliceCarController类担任了PoliceCar的创建职责,我们应将这项职责提取出来。

重构后

重构后PoliceCarController类就很直观了,New()方法被移除了。
现在它依赖于IPoliceCarFactory接口,PoliceCarController不需要知道PoliceCar的创建细节,PoliceCar的创建逻辑被这个工厂接口隔离开了。
这不仅精简了PoliceCarController的职责,也降低了PoliceCarController和PoliceCar之间的耦合性。

另外,原本PoliceCar对象的生命周期是由PoliceCarController管理的,重构后则由工厂类来管理的。
由工厂类来集中管理对象的生命周期,可以保证程序具有一致的行为(一致性)。

隐藏代码
public class PoliceCarController
{public IPoliceCarFactory PoliceCarFactory { get; set; }public PoliceCarController(IPoliceCarFactory policeCarFactory){PoliceCarFactory = policeCarFactory;}public PoliceCar New(int mileage, bool serviceRequired){return PoliceCarFactory.Create(mileage, serviceRequired);}
}public class PoliceCar
{public bool ServiceRequired { get; set; }public int Mileage { get; set; }
}public interface IPoliceCarFactory
{PoliceCar Create(int mileage, bool serviceRequired);
}public class PoliceCarFactory : IPoliceCarFactory
{public PoliceCar Create(int mileage, bool serviceRequired){PoliceCar policeCar = new PoliceCar();policeCar.ServiceRequired = serviceRequired;policeCar.Mileage = mileage;return policeCar;}
}

注意:阅读这段代码时,请将它看成两部分。
一部分是IPoliceCarFactory和PoliceCarFactory,另一部分是PoliceCarController和PoliceCar。

简单工厂模式介绍

我们所熟知的”工厂模式“有三种,它们也被称之为“工厂模式家族”,或者“工厂三兄弟”。

  • 简单工厂(Simple Factory)
  • 工厂方法(Factory Method)
  • 抽象工厂(Abstract Factory)。

本文中用到的就是简单工厂模式,这三者有很多不同的地方,运用场景也各不相同。
(由于本文不是专门 讲设计模式的,所以我在这里就不过多介绍它们的区别和运用场景了)

定义

Simple Factory Pattern:Creates objects without exposing the instantiation logic to the client. Refers to the newly created object through a common interface。

简单工厂模式由3部分组成:客户、工厂和产品。
用一句话可以概括为:客户需要的产品应由工厂创建,产品的实现细节不应该暴露给客户。
用户使用的iPhone手机是由富士康生产的,用户对应下图中的Client,iPhone对应Product,富士康则对应Factory,用户无需知道富士康是怎么生产iPhone的。

在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式需要专门定义一个类(或接口)来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

使用场景

简单工厂模式适用的场景如下:

  • 工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  • 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。
小酌重构系列目录汇总
关注keepfool

转载于:https://www.cnblogs.com/keepfool/p/5510674.html

小酌重构系列[17]——提取工厂类相关推荐

  1. 小酌重构系列[8]——提取接口

    前言 世间唯一"不变"的是"变化"本身,这句话同样适用于软件设计和开发. 在软件系统中,模块(类.方法)应该依赖于抽象,而不应该依赖于实现. 当需求发生&quo ...

  2. 路漫漫其修远兮,吾将上下而求索——小酌重构系列[0]开篇有益

    相信博客园的读者大多都是千万"码农"中的一员,每个人都写过很多代码,但并不是每一个人都能写出高质量的代码. rome is not built in one day !--完成高质 ...

  3. 小酌重构系列[19]——分解大括号

    概述 if else, for, while等是程序中最常用的语句,这些语句有一个共同点--它们的逻辑都封装在一对"{}"包围的代码块中.在实现复杂的业务逻辑时,会较多地用到这些语 ...

  4. 小酌重构系列[18]——重命名

    概述 代码是从命名开始的,我们给类.方法.变量和参数命名,我们也给解决方案.工程.目录命名.在编码时,除了应该遵守编程语言本身的命名规范外,我们应该提供好的命名.好的命名意味着良好的可读性,读你代码的 ...

  5. 小酌重构系列[4]——分解方法

    概述 "分解方法"的思想和前面讲到的"提取方法"."提取方法对象"基本一致. 它是将较大个体的方法不断的拆分,让每个"方法&quo ...

  6. 小酌重构系列[10]——分离职责

    概述 "分离职责"是经常使用的一个重构策略,当一个类担任的职责太多时,应按职责将它拆分成多个类,每个类分别承担"单一"的职责,也就是让每个类专心地做" ...

  7. 小酌重构系列[16]——引入契约式设计

    概述 试想这样一个场景,你提供了一些API给客户端调用,客户端传入了一些参数,然后根据这些参数执行了API逻辑,最终返回一个结果给客户端. 在这个场景中,有两个隐患,它们分别是: 客户端调用API时, ...

  8. 小酌重构系列[3]——方法、字段的提升和降低

    本文要介绍的是4种重构策略,它们分别是提升方法.降低方法.提升字段和降低字段. 由于这4种重构策略具有一定的相通性,所以我将它们放到一篇来讲解. 定义 以下是这4种策略的定义 提升方法:当子类的方法描 ...

  9. 小酌重构系列[20]——用条件判断代替异常

    小酌重构系列[20]--用条件判断代替异常 参考文章: (1)小酌重构系列[20]--用条件判断代替异常 (2)https://www.cnblogs.com/keepfool/p/5513946.h ...

最新文章

  1. c语言课程设计链表 文件,C语言课程设计第三节课:指针和链表使用     150809205...
  2. Loadrunner11点击录制脚本无响应,IE页面弹不出——解决方案汇总
  3. python【数据结构与算法】贝祖定理简单讲解
  4. 直接使用汇编编写 .NET Standard 库
  5. [十]JavaIO之FilterInputStream FilterOutputStream
  6. Android NIO(Noblocking I/O非阻塞I/O)小结
  7. 零基础学sql要多久_成人零基础学习钢琴,要多久能学会?
  8. 什么时候用到全排列_初学讲义之高中数学二十一:排列组合和二项式定理
  9. SpringMVC显示上传文件
  10. 【小程序源码】修复图片音频全新升级带特效神器小游戏微信小程序源码下载-多种游戏支持
  11. Bootstrap可视化布局
  12. 联想thinkpad待机怎么唤醒_笔记本睡眠怎么唤醒【步骤介绍】
  13. 新生学大学计算机心得,大学生信息技术心得体会怎么写
  14. excel 电阻并联计算_3个并联电阻计算公式 并联电阻计算公式计算方法
  15. BG22蓝牙——第四弹 联调单片机,蓝牙点灯Demo
  16. BERT的学习理解笔记
  17. 京东商城关键词SEO优化总结
  18. 最大公约数gcd(m,n)=gcd(n,m%n)之证明
  19. 配置网页登陆虚拟带库显示报错
  20. java对外接口 入参实体命名_支付中心接口设计之参数命名

热门文章

  1. 导航装备便携式综合测试工装
  2. 6.18大促,看蚂蚁智能客服如何帮你快人一步
  3. 一文读懂Android View事件分发机制
  4. informatica 许可_安装Informatica9.5.1
  5. IOS 监听slider滑动
  6. [转载整理]晚甘园红茶之醇活动之二-把杯叙红茶!
  7. CKH IOD选择通过CSG增强其数字批发和物联网客户体验
  8. 大数据复试面试总结(二)前沿技术相关
  9. 微信开源C++Libco介绍与应用(二)
  10. 史上最强《Java 开发手册》泰山版王者归来!