当前位置: 首页 > news >正文

用枚举实现工厂方法模式更简洁

工厂方法模式(Factory Method Patter)是"创建对象的接口",让子类决定实例化哪一个类,并使一个类的实例化延迟到其子类.工厂方法模式在我们的开发工作中,经常会用到.

下面以汽车制造为例,看看一般的工厂方法模式是如何实现的,代码如下:

复制代码
 1 public class Client {
 2     public static void main(String[] args) {
 3         //生产车辆
 4         Car car = CarFactory.createCar(FordCar.class);
 5     }
 6 }
 7 
 8 //抽象产品
 9 interface Car {
10 };
11 //具体产品类
12 class FordCar implements Car {
13 };
14 //具体产品类
15 class BuickCar implements Car {
16 };
17 //工厂类
18 class CarFactory {
19     //生产汽车
20     public static Car createCar(Class<? extends Car> c) {
21         try {
22             return (Car) c.newInstance();
23         } catch (Exception e) {
24             e.printStackTrace();
25         }
26         return null;
27     }
28 }
复制代码

这是最原始的工厂方法模式,有两个产品"福特骑车和别克骑车,然后通过工厂方法模式来生产,有了工厂方法模式,我们就不用关心一辆车具体是怎么生成的了,只要告诉工厂"给我生产一辆福特骑车"就可以了,下面是产出一辆福特骑车时客户端的代码:

 Car car = CarFactory.createCar(FordCar.class);

这就是我们经常使用的工厂方法模式,但经常使用不代表就是最优秀的,最简洁的.

此处在介绍一种通过枚举实现工厂方法模式的方案,谁优谁劣自行评价.枚举实现工厂方法模式有两种方法:

(1)枚举非静态方法实现工厂方法模式

我们知道每个枚举项都是该枚举的实例对象,那是不是定义一个方法可以生成每个枚举项的对应产品来实现此模式呢?代码如下:

复制代码
 1 public class Client {
 2     public static void main(String[] args) {
 3         //生产汽车
 4         Car car = CarFactory.BuickCar.create();
 5     }
 6 }
 7 
 8 interface Car {
 9 };
10 
11 class FordCar implements Car {
12 };
13 
14 class BuickCar implements Car {
15 };
16 
17 enum CarFactory {
18     //定义工厂类能生产汽车的类型
19     FordCar, BuickCar;
20     //生产汽车
21     public Car create() {
22         switch (this) {
23         case FordCar:
24             return new FordCar();
25         case BuickCar:
26             return new BuickCar();
27         default:
28             throw new AssertionError("无效参数");
29         }
30     }
31 }
复制代码

 create是一个非静态方法,也就是只有通过FordCar,BuickCar枚举项才能访问,采用这种方式实现工厂方法模式时,客户端要产生一辆汽车就很简单了.代码如下:

Car car = CarFactory.BuickCar.create();

 

(2)通过抽象方法生成产品

枚举类型虽然不能继承,但是可以用abstract修饰其方法,此时就标识该枚举是一个抽象枚举,需要每个枚举项自行实现该方法,也就说枚举项的类型是该枚举的一个子类,看代码:

复制代码
 1 public class Client {
 2     public static void main(String[] args) {
 3         Car car = CarFactory.BuickCar.create();
 4     }
 5 }
 6 
 7 interface Car {
 8 };
 9 
10 class FordCar implements Car {
11 };
12 
13 class BuickCar implements Car {
14 };
15 
16 enum CarFactory {
17     FordCar {
18         public Car create() {
19             return new FordCar();
20         }
21     },
22     BuickCar {
23         public Car create() {
24             return new BuickCar();
25         }
26     };
27     //抽象生产方法
28     public abstract Car create();
29 }
复制代码

 

首先定义一个抽象制造方法create,然后 每个枚举项自行实现,这种方式编译后会产生两个CarFactory的匿名子类,因为每个枚举项都 要实现抽象create方法,客户端的调用与上一个方案相同,不再赘述.

为什么使用枚举类型的工厂方法模式有以下三个优点:

(1)避免错误调用的发生

一般工厂方法模式中的生产方法(也就是createCar方法)可以接收三种类型的参数:类型参数(Class),String参数(生产方法中判断String参数是需要生产什么产品),int参数(根据int值判断需要生产什么类型的产品).

这三种参数都是宽泛的数据类型,很容易产生错误.比如边界问题,null值问题,而且出现这类错误编译器还不会报警.例如:

Car car = CarFactory.createCar(Car.class);

 

Car是一个接口,完全合乎createCar方法的要求,所以它在编译时不会报任何错误,但一运行起来就会报java.lang.InstantiationException异常,而使用枚举类型的工厂方法模式就不存在该问题.不需要传递任何参数,只需要选择好生产什么类型的产品就可以了.

(2)性能好,使用便捷.

枚举类型的计算是以int类型的计算为基础的,这是最基本的操作,性能当然快.

(3)降低类间的耦合

不管生产方法接收的是Class,String还是int参数,都会成为客户端类的负担.这些类并不是客户端需要的,而是因为工厂方法的限制必须输入的.******

 



本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/5633233.html,如需转载请自行联系原作者

相关文章:

  • 关于android.view.WindowLeaked异常的解决方案
  • 十六进制转化为ASCII码引起的的进制的故事
  • 1、虚拟机安装
  • apache虚拟主机用户验证
  • 013——数组(十三) array_push array_rand array_reverse
  • WPF/Silverlight Layout 系统概述——Measure
  • hadoop 测试第一个mapreduce程序
  • 【原】iOSCoreAnimation动画系列教程(二):CAKeyFrameAnimation【包会】
  • mockcpp的ApiHook实现原理
  • MySQL数据库字符集由utf8修改为utf8mb4一例
  • IDEA 9.0.2整合Tomcat开发
  • Tomcat多域名访问
  • bootstrap模态框垂直居中
  • 如何让你的python爬虫“拟人化”, 突破60秒不被ban,绝地求生!
  • python(58):python下划线
  • 4. 路由到控制器 - Laravel从零开始教程
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • css的样式优先级
  • golang中接口赋值与方法集
  • JavaScript中的对象个人分享
  • JS正则表达式精简教程(JavaScript RegExp 对象)
  • leetcode讲解--894. All Possible Full Binary Trees
  • SpiderData 2019年2月23日 DApp数据排行榜
  • Vue 2.3、2.4 知识点小结
  • 代理模式
  • 将回调地狱按在地上摩擦的Promise
  • 码农张的Bug人生 - 见面之礼
  • 免费小说阅读小程序
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 微服务核心架构梳理
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • ​MySQL主从复制一致性检测
  • ​用户画像从0到100的构建思路
  • !!Dom4j 学习笔记
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • #define、const、typedef的差别
  • #Z2294. 打印树的直径
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (javascript)再说document.body.scrollTop的使用问题
  • (rabbitmq的高级特性)消息可靠性
  • (ZT)一个美国文科博士的YardLife
  • (二)hibernate配置管理
  • (附源码)计算机毕业设计SSM智慧停车系统
  • (考研湖科大教书匠计算机网络)第一章概述-第五节1:计算机网络体系结构之分层思想和举例
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (欧拉)openEuler系统添加网卡文件配置流程、(欧拉)openEuler系统手动配置ipv6地址流程、(欧拉)openEuler系统网络管理说明
  • (实战篇)如何缓存数据
  • .NET 读取 JSON格式的数据
  • .Net+SQL Server企业应用性能优化笔记4——精确查找瓶颈
  • .NET6使用MiniExcel根据数据源横向导出头部标题及数据
  • .NET面试题解析(11)-SQL语言基础及数据库基本原理
  • @RequestBody的使用
  • [2016.7 test.5] T1
  • [Android]一个简单使用Handler做Timer的例子