菜鸟成长系列-概述
菜鸟成长系列-面向对象的四大基础特性
菜鸟成长系列-多态、接口和抽象类
菜鸟成长系列-面向对象的6种设计原则
菜鸟成长系列-单例模式java
上一篇咱们已经对建立型模式中的单例模式进行了学习,今天来学习另一个比较重要而且常用的模式-工厂模式;工厂模式专门负责将大量有共同接口的类实例化。其能够动态的决定将哪个类实例化,没必要事先知道每次要实例化哪个类。
bash
工厂模式具备如下三种形态:架构
本篇文章将对这三种形态的工厂模式进行一些基本的学习,并经过例子来直观的感觉下不一样形态的具体实现方式。最后再分析下JAVA以及Spring中是如何使用的。app
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();
}
复制代码
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();
}
}
复制代码
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();
}
}
复制代码
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("来自南方厨师作的鱼");
}
}
复制代码
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,这样咱们就知足了不一样区域同时关于鱼口味的需求了,之后升值加薪就期望他们了。。。
关于工厂方法模式的优缺点:
优势:
一、 在工厂方法中,用户只须要知道所要产品的具体工厂,无须关系具体的建立过程,甚至不须要具体产品类的类名。
二、 在系统增长新的产品时,咱们只须要添加一个具体产品类和对应的实现工厂,无需对原工厂进行任何修改,很好地符合了“开闭原则”
缺点:
每次增长一个产品时,都须要增长一个具体类和对象实现工厂,是的系统中类的个数成倍增长,在必定程度上增长了系统的复杂度,同时也增长了系统具体类的依赖。这并非什么好事。
准备吃饭的时候忽然又来了几位同事,并且他们有的喜欢吃酸菜鱼,有的喜欢吃红烧鱼,这就很头疼。因而,只能根据他们的须要继续点外卖。(这个就给出一个结构图,而且将每种角色都用具体的场景来讲明了,具体的代码能够参考这个图例本身尝试一下。)
java.text.DateFormat (一个抽象类)这个类相信不少小伙伴都用到过,在java API中,这个类算是一个简单工厂模式的典型应用了(此处仍是与上篇同样,不考虑期源码细节,也不介绍基本用法)。来看它的几个方法:
做为一个抽象类,却提供了不少的静态工厂方法,就像上面列举的那三个同样。有小伙伴可能会疑惑,为啥子一个抽象类阔以有本身的实例,并经过几个方法提供本身的实例。咱们知道,抽象类是不能够有本身的实例对象的,可是须要注意的是,DateFormat的工厂方法是静态的,并非普通的方法,也就是说,不须要经过建立实例对象的方式去调用。
public final static DateFormat getDateInstance()
{
return get(0, DEFAULT, 2, Locale.getDefault(Locale.Category.FORMAT));
}
复制代码
getDateInstance方法并无经过调用DateFormat的构造方法来建立对象。
java.net.URL类,类图以下,
根据java与模式一书的介绍,在java中使用抽象工厂模式的是 JAVA awt的peer架构,经过抽象工厂模式来构建分属于不一样操做系统的peer构件。这个我也没用过,了解便可。
关于Spring中工厂模式的使用会在后续Spring源码分析系列中给你们详细分析,这里就不重复了。
今天的学习就到此结束了,祝你们周末愉快。话说今天平安夜,你们都是在家写代码吗?
若是您对系列文章有任何意见,能够给我留言,感谢你们。
下面是一个接苹果的姿式,呼呼呼.....