菜鸟成长系列-工厂模式

菜鸟成长系列-概述
菜鸟成长系列-面向对象的四大基础特性
菜鸟成长系列-多态、接口和抽象类
菜鸟成长系列-面向对象的6种设计原则
菜鸟成长系列-单例模式java

上一篇咱们已经对建立型模式中的单例模式进行了学习,今天来学习另一个比较重要而且常用的模式-工厂模式;工厂模式专门负责将大量有共同接口的类实例化。其能够动态的决定将哪个类实例化,没必要事先知道每次要实例化哪个类。bash

工厂模式具备如下三种形态:架构

  • 简单工厂模式:又称静态工厂模式
  • 工厂方法模式:又称多态性工厂模式或者虚拟构造子模式
  • 抽象工厂模式:又称工具箱模式

本篇文章将对这三种形态的工厂模式进行一些基本的学习,并经过例子来直观的感觉下不一样形态的具体实现方式。最后再分析下JAVA以及Spring中是如何使用的。app

一、简单工厂模式

从上图能够看出,简单工厂模式涉及到工厂角色、抽象产品角色以及具体产品角色等三个角色。各角色职能以下:

  • 工厂类:担任这个角色的是工厂方法模式的核心,含有与应用紧密相关的具体业务逻辑。工厂类在客户端的直接调用下建立产品对象,它每每由一个具体的java类实现
  • 抽象产品:担任这个角色的类是工厂方法模式所建立的对象的父类,或它们共同拥有的接口。抽象产品角色能够用一个java接口或者抽象类来实现
  • 具体产品:工厂方法模式所建立的任何对象都是这个角色的实例,具体产品角色由一个java类实现

来看例子,考虑到今天有小伙伴来我这作客,本demo将以作菜来实现一波。首先工厂就是厨房,抽象类就是笼统的菜,实现类就是具体哪一个菜。

  • 抽象产品
package com.glmapper.design.factory;
/**
 * 抽象类角色:food接口,约束类型
 * @author glmapper
 * @date 2017年12月24日上午10:38:36
 *
 */
public interface IFood {
	/**
	 * 提供一个展现食物细节的方法
	 * @param foodName 食物名称
	 */
	public void showFood();
}

复制代码
  • 具体产品-鱼
package com.glmapper.design.factory;
/**
 * 具体产品-食物鱼
 * @author glmapper
 * @date 2017年12月24日上午10:51:29
 *
 */
public class FishFood implements IFood
{
	@Override
	public void showFood() {
		System.out.println("一盘鱼");
	}
}
复制代码
  • 具体产品-土豆丝
package com.glmapper.design.factory;
/**
 * 
 * 具体食物:土豆丝
 * @author glmapper
 * @date 2017年12月24日上午10:47:17
 *
 */
public class ShreddedPotatoesFood implements IFood{
	@Override
	public void showFood() {
		System.out.println("一盘土豆丝");
		
	}
}
复制代码
  • 工厂角色 - 食物工厂
package com.glmapper.design.factory;
/**
 * 工厂角色-食物工厂
 * 
 * @author glmapper
 * @date 2017年12月24日上午10:41:10
 *
 */
public class SimpleFoodFactory {
	/**
	 * 提供一个静态方法,用于获取食物
	 * @param foodType 食物类型
	 * @return 具体食物
	 */
	public static IFood getFood(String foodType){
		IFood food = null;
		if (foodType.equals("fish")) {
			food = new FishFood();
		}
		if (foodType.equals("potatoes")) {
			food = new ShreddedPotatoesFood();
		}
		return food;
	}
}
复制代码
  • 客户端
package com.glmapper.design.factory;
/**
 * 客户端
 * @author glmapper
 * @date 2017年12月24日上午10:45:17
 *
 */
public class MainTest {
	public static void main(String[] args) {
		IFood fishfood = SimpleFoodFactory.getFood("fish");
		fishfood.showFood();
		
		IFood potatoesfood = SimpleFoodFactory.getFood("potatoes");
		potatoesfood.showFood();
	}
}
复制代码
  • 结果
一盘鱼
一盘土豆丝
复制代码

OK,菜作完了,能够吃了。。。ide

咱们来讨论下简单工厂模式的优缺点:工具

优势:模式的核心是工厂类,这个类含有必要的判断逻辑,能够决定在何时建立哪个产品类的实例。而客户端则能够免除直接建立产品对象的责任,而仅仅负责消费产品便可。用一句话来讲就是:简单工厂模式这个作法实现了对责任的分割。
缺点:集中了全部产品的建立逻辑,造成了一个无所不能的全职类,可是以前咱们在讨论设计原则的时候说过,咱们要尽可能避免这种状况的发生,这种就很明显破坏了单一职责这条原则,另外也不知足开闭原则的约束。当咱们须要进行品类扩展时,咱们须要不断的去修改咱们的工厂的业务逻辑,一方面是工厂类会急速的膨胀,另外一方面由于囊括了不一样的产品对于咱们后期的维护形成必定的影响。源码分析

二、工厂方法模式

这个时候一个同事说他是南方人,另一个同事说他是北方人,吃不惯今天的菜。post

好吧,既然这样,那我就只能点外卖了。。。可是为了防止他们变卦本身的家乡,我须要作一个计划,下面就是计划图:

从上图中咱们能够看出,工厂方法模式的角色包括如下几种:学习

  • 抽象工厂:是工厂方法模式的核心,与应用程序无关。任何在模式中建立的对象的工厂类必须实现这个接口。
  • 具体工厂:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,而且受到应用程序调用以建立产品对象。
  • 抽象产品:工厂方法模式所建立的对象的超类型,也就是产品对象的共同父类或共同拥有的接口
  • 具体产品:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂建立,它们之间每每一一对应。

由于个人同事都是来自不一样地方的,他们的口味也都不同,可是呢同事都是第一次来我家吃饭,因此为了招待周全,根据同事不一样的口味叫不一样口味的鱼。ui

  • 抽象工厂角色:获取食物
package com.glmapper.design.factory;
/**
 * 
 * 角色1:抽象工厂 - 负责获取食物
 * @author glmapper
 * @date 2017年12月24日下午1:59:28
 */
public interface MethodFoodFactory {
	//获取食物的方法
	public IFishFood getFood();
}
复制代码
  • 具体工厂1:获取南方食物-鱼
package com.glmapper.design.factory;
/**
 * 南方口味外卖 - 鱼
 * @author glmapper
 * @date 2017年12月24日下午2:03:36
 */
public class SouthFishFactory implements MethodFoodFactory{
	@Override
	public IFishFood getFood() {
		return new SouthFishFood();
	}
}

复制代码
  • 具体工厂2:获取北方食物-鱼
package com.glmapper.design.factory;
/**
 * 北方口味外卖 - 鱼
 * @author glmapper
 * @date 2017年12月24日下午2:03:36
 */
public class NorthFishFactory implements MethodFoodFactory{

	@Override
	public IFishFood getFood() {
		// TODO Auto-generated method stub
		return new NorthFishFood();
	}
}
复制代码
  • 具体产品1:南方食物- 鱼
package com.glmapper.design.factory;
/**
 * 南方口味-鱼
 * @author glmapper
 * @date 2017年12月24日下午2:16:17
 */
public class SouthFishFood implements IFishFood{
	@Override
	public void showFood() {
		System.out.println("来自南方厨师作的鱼");
	}
}
复制代码
  • 具体产品2:北方食物-鱼
package com.glmapper.design.factory;
/**
 * 北方口味  - 鱼
 * @author glmapper
 * @date 2017年12月24日下午2:12:55
 */
public class NorthFishFood implements IFishFood {
	@Override
	public void showFood() {
		System.out.println("来自北方厨师作的鱼");
	}
}
复制代码
  • 客户端
package com.glmapper.design.factory;
/**
 * 客户端
 * @author glmapper
 * @date 2017年12月24日上午10:45:17
 */
public class MainTest {
	public static void main(String[] args) {
		//点一个南方口味外卖
		MethodFoodFactory southFoodFactory = new SouthFishFactory();
		//点一个北方口味外卖
		MethodFoodFactory northFoodFactory = new NorthFishFactory();
		//拿到南方口味外卖鱼
		southFoodFactory.getFood().showFood();
		//拿到北方口味外卖鱼
		northFoodFactory.getFood().showFood();
	}
}
复制代码
  • 结果:
来自南方厨师作的鱼
来自北方厨师作的鱼
复制代码

OK,这样咱们就知足了不一样区域同时关于鱼口味的需求了,之后升值加薪就期望他们了。。。

关于工厂方法模式的优缺点:

优势:
一、 在工厂方法中,用户只须要知道所要产品的具体工厂,无须关系具体的建立过程,甚至不须要具体产品类的类名。
二、 在系统增长新的产品时,咱们只须要添加一个具体产品类和对应的实现工厂,无需对原工厂进行任何修改,很好地符合了“开闭原则”
缺点:
每次增长一个产品时,都须要增长一个具体类和对象实现工厂,是的系统中类的个数成倍增长,在必定程度上增长了系统的复杂度,同时也增长了系统具体类的依赖。这并非什么好事。

三、抽象工厂模式

准备吃饭的时候忽然又来了几位同事,并且他们有的喜欢吃酸菜鱼,有的喜欢吃红烧鱼,这就很头疼。因而,只能根据他们的须要继续点外卖。(这个就给出一个结构图,而且将每种角色都用具体的场景来讲明了,具体的代码能够参考这个图例本身尝试一下。)

OK,终于能够吃饭了!

四、三种形态的工厂模式在java中的使用

4.一、简单工厂模式在java中的使用

java.text.DateFormat (一个抽象类)这个类相信不少小伙伴都用到过,在java API中,这个类算是一个简单工厂模式的典型应用了(此处仍是与上篇同样,不考虑期源码细节,也不介绍基本用法)。来看它的几个方法:

  • public final static DateFormat getDateInstance()
  • public final static DateFormat getDateInstance(int style)
  • public final static DateFormat getDateInstance(int style, Locale aLocale)

做为一个抽象类,却提供了不少的静态工厂方法,就像上面列举的那三个同样。有小伙伴可能会疑惑,为啥子一个抽象类阔以有本身的实例,并经过几个方法提供本身的实例。咱们知道,抽象类是不能够有本身的实例对象的,可是须要注意的是,DateFormat的工厂方法是静态的,并非普通的方法,也就是说,不须要经过建立实例对象的方式去调用。

public final static DateFormat getDateInstance()
{
    return get(0, DEFAULT, 2, Locale.getDefault(Locale.Category.FORMAT));
}
复制代码

getDateInstance方法并无经过调用DateFormat的构造方法来建立对象。

4.二、工厂方法模式在java中的应用

java.net.URL类,类图以下,

URL对象经过一个工厂方法openConnection()返回一个URLConnection类型的对象。URLConnection是一个抽象类,所以所返还的不多是这个抽象类的实例,而必然是其具体子类的实例。

4.三、抽象工厂模式在java中的应用

根据java与模式一书的介绍,在java中使用抽象工厂模式的是 JAVA awt的peer架构,经过抽象工厂模式来构建分属于不一样操做系统的peer构件。这个我也没用过,了解便可。

关于Spring中工厂模式的使用会在后续Spring源码分析系列中给你们详细分析,这里就不重复了。

今天的学习就到此结束了,祝你们周末愉快。话说今天平安夜,你们都是在家写代码吗?

若是您对系列文章有任何意见,能够给我留言,感谢你们。

下面是一个接苹果的姿式,呼呼呼.....

相关文章
相关标签/搜索