[改善Java代码]用枚举实现工厂方法模式更简洁
工厂方法模式(Factory Method Patter)是"创建对象的接口",让子类决定实例化哪一个类,并使一个类的实例化延迟到其子类.工厂方法模式在我们的开发工作中,经常会用到.
下面以汽车制造为例,看看一般的工厂方法模式是如何实现的,代码如下:
public class Client {
public static void main(String[] args) {
//生产车辆
Car car = CarFactory.createCar(FordCar.class);
}
}
//抽象产品
interface Car {
};
//具体产品类
class FordCar implements Car {
};
//具体产品类
class BuickCar implements Car {
};
//工厂类
class CarFactory {
//生产汽车
public static Car createCar(Class<? extends Car> c) {
try {
return (Car) c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
这是最原始的工厂方法模式,有两个产品"福特骑车和别克骑车,然后通过工厂方法模式来生产,有了工厂方法模式,我们就不用关心一辆车具体是怎么生成的了,只要告诉工厂"给我生产一辆福特骑车"就可以了,下面是产出一辆福特骑车时客户端的代码:
Car car = CarFactory.createCar(FordCar.class);
这就是我们经常使用的工厂方法模式,但经常使用不代表就是最优秀的,最简洁的.
此处在介绍一种通过枚举实现工厂方法模式的方案,谁优谁劣自行评价.枚举实现工厂方法模式有两种方法:
(1)枚举非静态方法实现工厂方法模式
我们知道每个枚举项都是该枚举的实例对象,那是不是定义一个方法可以生成每个枚举项的对应产品来实现此模式呢?代码如下:
public class Client {
public static void main(String[] args) {
//生产汽车
Car car = CarFactory.BuickCar.create();
}
}
interface Car {
};
class FordCar implements Car {
};
class BuickCar implements Car {
};
enum CarFactory {
//定义工厂类能生产汽车的类型
FordCar, BuickCar;
//生产汽车
public Car create() {
switch (this) {
case FordCar:
return new FordCar();
case BuickCar:
return new BuickCar();
default:
throw new AssertionError("无效参数");
}
}
}
create是一个非静态方法,也就是只有通过FordCar,BuickCar枚举项才能访问,采用这种方式实现工厂方法模式时,客户端要产生一辆汽车就很简单了.代码如下:
Car car = CarFactory.BuickCar.create();
(2)通过抽象方法生成产品
枚举类型虽然不能继承,但是可以用abstract修饰其方法,此时就标识该枚举是一个抽象枚举,需要每个枚举项自行实现该方法,也就说枚举项的类型是该枚举的一个子类,看代码:
public class Client {
public static void main(String[] args) {
Car car = CarFactory.BuickCar.create();
}
}
interface Car {
};
class FordCar implements Car {
};
class BuickCar implements Car {
};
enum CarFactory {
FordCar {
public Car create() {
return new FordCar();
}
},
BuickCar {
public Car create() {
return new BuickCar();
}
};
//抽象生产方法
public abstract Car create();
}
首先定义一个抽象制造方法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参数,都会成为客户端类的负担.这些类并不是客户端需要的,而是因为工厂方法的限制必须输入的.******
下一次,使用枚举来实现工厂方法模式.
[改善Java代码]用枚举实现工厂方法模式更简洁的更多相关文章
- Java设计模式(二) 工厂方法模式
本文介绍了工厂方法模式的概念,优缺点,实现方式,UML类图,并介绍了工厂方法(未)遵循的OOP原则 原创文章.同步自作者个人博客 http://www.jasongj.com/design_patte ...
- JAVA设计模式——第 5 章 工厂方法模式【Factory Method Pattern】(转)
女娲补天的故事大家都听说过吧,今天不说这个,说女娲创造人的故事,可不是“造人”的工作,这个词被现代人滥用了.这个故事是说,女娲在补了天后,下到凡间一看,哇塞,风景太优美了,天空是湛蓝的,水是清澈的,空 ...
- Java描述设计模式(03):工厂方法模式
本文源码:GitHub·点这里 || GitEE·点这里 一.工厂方法模式 1.生活场景 系统常见的数据导出功能:数据导出PDF.WORD等常见格式. 2.工厂方法模式 是类的创建模式,又叫做虚拟构造 ...
- Java设计模式(四)工厂方法模式
定义与类型 定义:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行. 类型:创建型 适用场景 创建对象需要大量重复的代码 客户端(应用层)不依赖于产 ...
- java 23 - 1 设计模式之工厂方法模式
转载: JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式)
- Java设计模式菜鸟系列(四)工厂方法模式建模与实现
转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39760895 工厂方法模式(Factory Method) 工厂方法:顾名思义,就是调用工 ...
- Java设计模式学习笔记(三) 工厂方法模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...
- Java设计模式:Factory Method(工厂方法)模式
概念定义 工厂方法(Factory Method)模式,又称多态工厂(Polymorphic Factory)模式或虚拟构造器(Virtual Constructor)模式.工厂方法模式通过定义工厂抽 ...
- [改善Java代码]推荐覆写toString方法
建议49: 推荐覆写toString方法 为什么要覆写toString方法,这个问题很简单,因为Java提供的默认toString方法不友好,打印出来看不懂,不覆写不行,看这样一段代码: public ...
随机推荐
- JavaScript快排与原生sort的测试
今天工作室断网!果断回宿舍,不然各种资料都没有.(他说将来会找到!)不好意思,又哼起来了.进入主题,大家都知道,快排是各种排序算法中,最高效的也是应用最广的,还有更重要的一点,面试特别爱考的! 其实大 ...
- nginx 502 错误
今天帮朋友处理一个程序报错,重启nginx服务之后,发现首页打不开了,但是静态文件可以打开 经检查nginx 服务器正常运行,重启无数次仍然502错误,考虑到静态文件可以打开,怀疑可能是php 脚本程 ...
- Spring AOP + AspectJ annotation example
In this tutorial, we show you how to integrate AspectJ annotation with Spring AOP framework. In simp ...
- C++中使用函数指针 【瓦特芯笔记】
在C++类中使用函数指针. 类型定义: typedef 返回类型(类名::*新类型)(参数表) //类定义 class CA { public: char lcFun(int a) ...
- MyEclipse10.0 安装 jbpm4.4
马上送上地址:http://sourceforge.net/projects/jbpm/files/jBPM%204/ 偶这里下载的是 jbpm4.4 如图: 1.点击 add site 2.点击 a ...
- 通过克隆MAC地址 破解网通电信封路由
通过克隆MAC地址 破解网通电信封路由 电信封路由方法一:先确定申请上网的电脑单机状态下已经能够上网.就说明该电脑网卡的MAC地址是合法的MAC地址.进入系统的MSDOS方式,发布ipconfig/a ...
- 关于DateTime.Now.Ticks
DataTime.Now.Ticks 的值表示自 0001 年 1 月 1 日午夜 12:00:00 以来所经历的以 100 纳秒为间隔的间隔数,可用于较精确的计时. 1秒=1000豪秒 1毫秒=10 ...
- Windows服务监视,如果停止则启动
1.已新建好Windows服务监视器: 2.新建恢复: 注:恢复目标需要为监视器目标的子集 3.使用命令行方式: 运行PS脚本(脚本位于目标计算机本地): 运行VBS脚本: 4.设置完成
- Spring-AOP和AspectJ的区别和联系
AOP是Spring框架的重要组成部分.目前我所接触的AOP实现框架有Spring AOP还有就是AspectJ(还有另外几种我没有接触过).我们先来说说他们的区别: AspectJ是一个比较牛逼的A ...
- JavaScrip基础讲座 - 神奇的ProtoType
1. 什么是 prototype prototype 对于 JavaScript 的 意义重大,prototype 不仅仅是一种管理对象继承的机制,更是一种出色的设计思想 在现实生活中,我们常常说, ...