工厂方法模式(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代码]用枚举实现工厂方法模式更简洁的更多相关文章

  1. Java设计模式(二) 工厂方法模式

    本文介绍了工厂方法模式的概念,优缺点,实现方式,UML类图,并介绍了工厂方法(未)遵循的OOP原则 原创文章.同步自作者个人博客 http://www.jasongj.com/design_patte ...

  2. JAVA设计模式——第 5 章 工厂方法模式【Factory Method Pattern】(转)

    女娲补天的故事大家都听说过吧,今天不说这个,说女娲创造人的故事,可不是“造人”的工作,这个词被现代人滥用了.这个故事是说,女娲在补了天后,下到凡间一看,哇塞,风景太优美了,天空是湛蓝的,水是清澈的,空 ...

  3. Java描述设计模式(03):工厂方法模式

    本文源码:GitHub·点这里 || GitEE·点这里 一.工厂方法模式 1.生活场景 系统常见的数据导出功能:数据导出PDF.WORD等常见格式. 2.工厂方法模式 是类的创建模式,又叫做虚拟构造 ...

  4. Java设计模式(四)工厂方法模式

    定义与类型 定义:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行. 类型:创建型 适用场景 创建对象需要大量重复的代码 客户端(应用层)不依赖于产 ...

  5. java 23 - 1 设计模式之工厂方法模式

    转载: JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式)

  6. Java设计模式菜鸟系列(四)工厂方法模式建模与实现

    转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39760895 工厂方法模式(Factory Method) 工厂方法:顾名思义,就是调用工 ...

  7. Java设计模式学习笔记(三) 工厂方法模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...

  8. Java设计模式:Factory Method(工厂方法)模式

    概念定义 工厂方法(Factory Method)模式,又称多态工厂(Polymorphic Factory)模式或虚拟构造器(Virtual Constructor)模式.工厂方法模式通过定义工厂抽 ...

  9. [改善Java代码]推荐覆写toString方法

    建议49: 推荐覆写toString方法 为什么要覆写toString方法,这个问题很简单,因为Java提供的默认toString方法不友好,打印出来看不懂,不覆写不行,看这样一段代码: public ...

随机推荐

  1. 转】Maven学习总结(五)——聚合与继承

    原博文出自于: http://www.cnblogs.com/xdp-gacl/p/4058008.html 感谢! 一.聚合 如果我们想一次构建多个项目模块,那我们就需要对多个项目模块进行聚合 1. ...

  2. AVD设置屏幕大小

    相关资料: 1.http://jingyan.baidu.com/article/fedf0737775d2835ac897700.html

  3. SpringDataMongoDB介绍(一)-入门

    SpringDataMongoDB介绍(一)-入门 本文介绍如何应用SpringDataMongoDB操作实体和数据库,本文只介绍最基本的例子,复杂的例子在后面的文章中介绍. SpringDataMo ...

  4. C++中#include包含头文件带 .h 和不带 .h 的区别

    C++中#include包含头文件带 .h 和不带 .h 的区别? 如 #include <iostream> 和 #include <iostream.h> 包含的东西有哪些 ...

  5. HDU 3974 Assign the task (DFS序 + 线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3974 给你T组数据,n个节点,n-1对关系,右边的是左边的父节点,所有的值初始化为-1,然后给你q个操 ...

  6. OOP 6大基本原则

    1.开闭原则: 对扩展开发.对修改关闭. 2.里氏替换原则:子类替换父类(可以用父类对象的任何地方都可以用子类对象代替) 3.依赖倒置原则:程序要依赖于抽象接口,不要依赖于具体实现.简单的说就是要求对 ...

  7. 介绍50个 WordPress 动作挂钩

    WordPress 之所以能成为世界上最受欢迎的网页内容管理系统,原因就在于它的高度灵活性和可塑性,而这种灵活性和可塑性正是由“挂钩”(Hooks)简洁宜用的结构所决定的.可以说,没有过滤挂钩(Fil ...

  8. Oracle-11g-R2 于 Linux 上的 RAC 卸载

    安装环境: SuSE Linux Enterprise Server 11 SP3 Oracle 11g 11.2.0.3   卸载步骤: 1.卸载 Database 软件(oracle,第一节点) ...

  9. Enhancing the Scalability of Memcached

    原文地址: https://software.intel.com/en-us/articles/enhancing-the-scalability-of-memcached-0 1 Introduct ...

  10. Ubuntu的力量何在?

    = 怎样正确评价Ubuntu,这不是一个简单问题.Ubuntu的 力量何在?它的意义何在?这都是须要认真研究的. 实际上,Uuntu 14.04 LTS公布之后,并没有引起预期的热烈反响.这是什么原因 ...