文档章节

Java工厂模式

ThinkGem
 ThinkGem
发布于 2016/07/17 16:51
字数 2865
阅读 725
收藏 3
点赞 0
评论 0

看着这篇文章些的不错,转了来,原文:http://blog.csai.cn/user1/25929/archives/2009/35622.html

 

一、引子
话说十年前,有一个爆发户,他家有三辆汽车(Benz(奔驰)、Bmw(宝马)、Audi(奥迪)看来这人比较爱国,没有日本车),还雇了司机为他开车。不过,爆发户坐车时总是这样:上Benz车后跟司机说"开奔驰车!",坐上Bmw后他说"开宝马车!",坐上Audi后他说"开奥迪车!"你一定说:这人有病!直接说开车不就行了?! 而当把这个爆发户的行为放到我们程序语言中来,我们发现C语言一直是通过这种方式来坐车的!幸运的是,这种有病的现象在OO语言中可以避免了。下面以Java语言为基础来引入我们本文的主题:工厂模式!!

二、简介
工厂模式主要是为创建对象提供了接口。工厂模式按照《Java与模式》中的提法分为三类:
1. 
简单工厂模式(Simple Factory) 
2. 
工厂方法模式(Factory Method) 
3. 
抽象工厂模式(Abstract Factory) 
这三种模式从上到下逐步抽象,并且更具一般性。还有一种分类法,就是将简单工厂模式看为工厂方法模式的一种特例,两个归为一类。下面是使用工厂模式的两种情况:
1.
在编码时不能预见需要创建哪种类的实例。
2.
系统不应依赖于产品类实例如何被创建、组合和表达的细节

 
三、简单工厂模式
顾名思义,这个模式本身很简单,而且使用在业务较简单的情况下。
它由三种角色组成(关系见下面的类图):
1、工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑。在java中它往往由一个具体类实现。
2、抽象产品角色:它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。
3、具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。

那么简单工厂模式怎么用呢?我来举个例子吧,我想这个比讲一大段理论上的文字描述要容易理解的多!下面就来给那个暴发户治病: P 
在使用了简单工厂模式后,现在暴发户只需要坐在车里对司机说句:"开车"就可以了。来看看怎么实现的:
//
抽象产品角色 
public interface Car{ 
public void drive(); 
}

//具体产品角色 
public class Benz implements Car{ 
public void drive() { 
System.out.println("Driving Benz "); 

}

public class Bmw implements Car{ 
public void drive() { 
System.out.println("Driving Bmw "); 


。。。(奥迪我就不写了:P

//工厂类角色 
public class Driver{

//工厂方法
//
注意 返回类型为抽象产品角色 
public static Car driverCar(String s)throws Exception {

//判断逻辑,返回具体的产品角色给Client 
if(s.equalsIgnoreCase("Benz")) return new Benz(); 
else if(s.equalsIgnoreCase("Bmw")) 
return new Bmw();

...... 
else throw new Exception(); 
。。。

// 欢迎暴发户出场...... 
public class Magnate{ 
public static void main(String[] args){ 
try{ 
//
告诉司机我今天坐奔驰
Car car = Driver.driverCar("benz"); 
//
下命令:开车
car.drive(); 
。。。
如果将所有的类放在一个文件中,请不要忘记只能有一个类被声明为public
 程序中类之间的关系如下:

这便是简单工厂模式了。下面是其好处:
首先,使用了简单工厂模式后,我们的程序不在"有病",更加符合现实中的情况;而且客户端免除了直接创建产品对象的责任,而仅仅负责"消费"产品(正如暴发户所为)。
下面我们从开闭原则上来分析下简单工厂模式。当暴发户增加了一辆车的时候,只要符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。那么对于产品部分来说,它是符合开闭原则的--对扩展开放、对修改关闭;但是工厂部分好像不太理想,因为每增加一辆车,都要在工厂类中增加相应的商业逻辑和判断逻辑,这显自然是违背开闭原则的。
对于这样的工厂类(在我们的例子中是为司机师傅),我们称它为全能类或者上帝类。
我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝类坏了,进而累坏了我们可爱的程序员:( 
正如我前面提到的简单工厂模式适用于业务将简单的情况下。而对于复杂的业务环境可能不太适应阿。这就应该由工厂方法模式来出场了!!

四、工厂方法模式
先来看下它的组成吧:
1、抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
2、具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。
3、抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
4、具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
来用类图来清晰的表示下的它们之间的关系:


我们还是老规矩使用一个完整的例子来看看工厂模式各个角色之间是如何来协调的。话说暴发户生意越做越大,自己的爱车也越来越多。这可苦了那位司机师傅了,什么车它都要记得,维护,都要经过他来使用!于是暴发户同情他说:看你跟我这么多年的份上,以后你不用这么辛苦了,我给你分配几个人手,你只管管好他们就行了!于是,工厂方法模式的管理出现了。代码如下:
//
抽象产品角色,具体产品角色与简单工厂模式类似,只是变得复杂了些,这里略。
//
抽象工厂角色
public interface Driver{ 
public Car driverCar(); 

public class BenzDriver implements Driver{ 
public Car driverCar(){ 
return new Benz(); 


public class BmwDriver implements Driver{ 
public Car driverCar() { 
return new Bmw(); 


......//
应该和具体产品形成对应关系,这里略... 
//
有请暴发户先生 
public class Magnate 

public static void main(String[] args) 

try{ 
Driver driver = new BenzDriver();

Car car = driver.driverCar(); 
car.drive(); 
}catch(Exception e) 
{ } 


工厂方法使用一个抽象工厂角色作为核心来代替在简单工厂模式中使用具体类作为核心。让我们来看看工厂方法模式给我们带来了什么?使用开闭原则来分析下工厂方法模式。当有新的产品(即暴发户的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码。看来,工厂方法模式是完全符合开闭原则的!
使用工厂方法模式足以应付我们可能遇到的大部分业务需求。但是当产品种类非常多时,就会出现大量的与之对应的工厂类,这不应该是我们所希望的。所以我建议在这种情况下使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实现。
当然特殊的情况,就要特殊对待了:对于系统中存在不同的产品树,而且产品树上存在产品族,那么这种情况下就可能可以使用抽象工厂模式了。

五、小结
让我们来看看简单工厂模式、工厂方法模式给我们的启迪:
如果不使用工厂模式来实现我们的例子,也许代码会减少很多--只需要实现已有的车,不使用多态。但是在可维护性上,可扩展性上是非常差的(你可以想象一下,添加一辆车后要牵动的类)。因此为了提高扩展性和维护性,多写些代码是值得的。

六、抽象工厂模式
先来认识下什么是产品族:位于不同产品等级结构中,功能相关联的产品组成的家族。如果光看这句话就能清楚的理解这个概念,我不得不佩服你啊。还是让我们用一个例子来形象地说明一下吧。

图中的BmwCarBenzCar就是两个产品树(产品层次结构);而如图所示的BenzSportsCarBmwSportsCar就是一个产品族。他们都可以放到跑车家族中,因此功能有所关联。同理BmwBussinessCarBenzSportsCar也是一个产品族。
回到抽象产品模式的话题上,可以这么说,它和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象。而且使用抽象工厂模式还要满足一下条件:
1.
系统中有多个产品族,而系统一次只可能消费其中一族产品
2.
同属于同一个产品族的产品以其使用。
来看看抽象工厂模式的各个角色(和工厂方法的如出一辙):
抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。
抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。

 

看过了前两个模式,对这个模式各个角色之间的协调情况应该心里有个数了,我就不举具体的例子了。只是一定要注意满足使用抽象工厂模式的条件哦,不然即使存在了多个产品树,也存在产品族,但是不能使用的。

 

本文转载自:http://thinkgem.iteye.com/blog/1153209

共有 人打赏支持
ThinkGem

ThinkGem

粉丝 856
博文 135
码字总数 20086
作品 1
济南
架构师
java开发中的常用的设计模式

设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代...

qq_38024548 ⋅ 05/28 ⋅ 0

简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别

转载:原地址http://www.cnblogs.com/zhangchenliang/p/3700820.html 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别 结合简单示例和UML图,讲解工厂模式简单原理。 一、引子 话说...

法斗斗 ⋅ 05/08 ⋅ 0

为什么我墙裂建议大家使用枚举来实现单例。

关于单例模式,我的博客中有很多文章介绍过。作为23种设计模式中最为常用的设计模式,单例模式并没有想象的那么简单。因为在设计单例的时候要考虑很多问题,比如线程安全问题、序列化对单例的...

⋅ 06/10 ⋅ 0

Java 设计模式 之 单例模式 Singleton 实际应用

Java 设计模式 之 单例模式 Singleton 实际应用 http://www.verejava.com/?id=16998954233354

verejava ⋅ 05/24 ⋅ 0

Java篇-接口interface关键字

一 : interface关键字 接口是与类并行的一个概念 Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,...

TianTianBaby223 ⋅ 04/24 ⋅ 0

Java 设计模式(14) —— 复合模式

一、复合模式 模式常一起使用,组合在一个设计解决方案中 复合模式在一个解决方案中结合两个或多个模式,能解决一般性或一系列的问题 二、示例 本次设计模式讲解中无代码示例,由于复合模式是...

磊_lei ⋅ 05/26 ⋅ 0

【唯品会】设计模式在特卖会的应用与思考

设计模式在特卖会的应用与思考 无心之心,道之所存 --《建筑的永恒之道》 1、开篇 之所以讨论设计模式,是因为当前我们都明白它可以提供优雅的解决方案,有利于在团队项目中建立共识,并且无...

暗夜在火星 ⋅ 2016/11/12 ⋅ 0

Decorator设计模式的实现中 装饰设计模式学习笔记

装饰设计模式 a)当某个类的某个方法不适应当前业务的需要 思路: 》扩展父类的可供扩展的方法,可以使有,但不优 》装饰设计模式(推荐) 开发步骤: 5)对于满足需求的方法,直接调用被包装的对...

知止内明 ⋅ 04/19 ⋅ 0

Java设计模式之单例设计模式

Java单例设计模式,有多种实现方式,下面介绍一下比较著名的一些实现方式 饿汉式 这种设计模式简单,且没有多线程安全问题,一般实际开发时选用这种方式。 class HungeryDemo{private Hunger...

技术小胖子 ⋅ 2017/11/08 ⋅ 0

详解Proxy代理模式的场景分析

代理模式是一个十分优秀的软件架构模式,许多应用都用到了代理模式。代理模式就是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不合适或者不能直接引用另一个对象,...

Java架构 ⋅ 05/30 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Netweaver和SAP云平台的quota管理

Netweaver 以需要为一个用户上下文(User Context)能够在SAP extended memory区域中分配内存尺寸创建quota为例。 对于Dialog工作进程,使用事务码修改参数 ztta/roll_extension_dia. 对于非D...

JerryWang_SAP ⋅ 27分钟前 ⋅ 0

IDEA提示编码速度

焦点移动 将焦点冲代码编辑窗口移动到菜单栏:Alt+菜单栏带下划线字母 将焦点从工具窗口移动到代码编辑窗口 Esc或Shift+Esc 将焦点从代码编辑移动到最近使用的工具窗口 F12 模板提示 Ctrl+J...

bithup ⋅ 36分钟前 ⋅ 0

180623-SpringBoot之logback配置文件

SpringBoot配置logback 项目的日志配置属于比较常见的case了,之前接触和使用的都是Spring结合xml的方式,引入几个依赖,然后写个 logback.xml 配置文件即可,那么在SpringBoot中可以怎么做?...

小灰灰Blog ⋅ 今天 ⋅ 0

冒泡排序

原理:比较两个相邻的元素,将值大的元素交换至右端。 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第...

人觉非常君 ⋅ 今天 ⋅ 0

Vagrant setup

安装软件 brew cask install virtualboxbrew cask install vagrant 创建project mkdir -p mst/vmcd mst/vmvagrant init hashicorp/precise64vagrant up hashicorp/precise64是一个box......

遥借东风 ⋅ 今天 ⋅ 0

python3.6 安装pyhook_3

我的是在win下的,忙了半天老是安装不了, pip install 也不行。 那么可以看出自己的版本是32bit 一脸懵逼 没办法 只好下载32版本的来安装 我一直以为 是 对应32 位的 。 下面是 小例子 http...

之渊 ⋅ 今天 ⋅ 0

004、location正则表达式

1、location的作用 location指令的作用是根据用户请求的URI来执行不同的应用,也就是根据用户请求的网站URL进行匹配,匹配成功即进行相关的操作。 2、location的语法 = 开头表示精确匹配 ^~...

北岩 ⋅ 今天 ⋅ 0

CentOS7 静默安装 Oracle 12c

环境 CentOS7.5 最小安装 数据库软件 linuxx64_12201_database.zip 操作系统配置 关闭 SELinux sed -i '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config 关闭防火墙 systemctl disable ......

Colben ⋅ 今天 ⋅ 0

Yii2中findAll()的正确使用姿势/返回为空的处理办法

从一次错误的操作开始 $buildingObject = Building::findAll("status=1"); 1 这个调用看着没有任何毛病,但是在使用时返回的结果却是一个空数组。再回过头来看看数据表中: 按照套路来讲,查...

dragon_tech ⋅ 今天 ⋅ 0

如何优雅的编程——C语言界面的一点小建议

我们鼓励在编程时应有清晰的哲学思维,而不是给予硬性规则。我并不希望你们能认可所有的东西,因为它们只是观点,观点会随着时间的变化而变化。可是,如果不是直到现在把它们写在纸上,长久以...

柳猫 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部