第4章 工厂模式

  在介绍工厂模式之前,先让我们来看一个例子。

  这里有一个Pizza类,用来生产pizza,并返回对象,具体代码如下:

  1. package com.ek.factory.simple;
  2.  
  3. import com.ek.factory.Pizza;
  4. import com.ek.factory.pizza.CheesePizza;
  5. import com.ek.factory.pizza.GreekPizza;
  6. import com.ek.factory.pizza.PepperoniPizza;
  7.  
  8. /**
  9. * @包名 com.ek.factory.simple
  10. * @文件名 PizzaStore.java
  11. * @作者 edi_kai
  12. * @创建日期 2015年8月25日
  13. * @版本 V 1.0
  14. * @描述
  15. */
  16. public class PizzaStore {
  17.  
  18. Pizza pizza;
  19. public Pizza orderPizza(String type) {
  20.  
  21. if (type.equals("cheese")) {
  22. this.pizza = new CheesePizza();
  23. }else if (type.equals("greek")) {
  24. this.pizza = new GreekPizza();
  25. }else if (type.equals("pepperoni")) {
  26. this.pizza = new PepperoniPizza();
  27. }
  28.  
  29. this.pizza.prepare();
  30. this.pizza.bake();
  31. this.pizza.cut();
  32. this.pizza.box();
  33.  
  34. return this.pizza;
  35. }
  36. }

  这代码有什么问题呢?如果我在添加一种类型的pizza或者某种pizza卖的不好我想下架,这时候,我们就只能去修改PizzaStore这个类,当只有一个pizza商店的时候或许觉不出什么问题来,但是,当我们有好几个连锁店的时候,必须去修改每个PizzaStore类,这是有悖设计原则的,面向修改关闭,面向扩展开放。

  那么我们接下来又该怎么修改呢?想一下,OO的设计原则(找出代码中需要变化的地方,将其独立出来,与不变的代码相分离,以便日后维护和扩展),接下我们对代码进行优化,进而得到了经过简单工厂模式设计之后的类图和代码,如下:

  1. package com.ek.factory.simple;
  2.  
  3. import com.ek.factory.Pizza;
  4. import com.ek.factory.pizza.CheesePizza;
  5. import com.ek.factory.pizza.GreekPizza;
  6. import com.ek.factory.pizza.PepperoniPizza;
  7.  
  8. /**
  9. * @包名 com.ek.factory.simple
  10. * @文件名 SimplePizzaFactory.java
  11. * @作者 edi_kai
  12. * @创建日期 2015年8月25日
  13. * @版本 V 1.0
  14. * @描述 这是pizza的简单工厂
  15. */
  16. public class SimplePizzaFactory {
  17.  
  18. Pizza pizza;
  19.  
  20. public Pizza createPizza(String type){
  21. if (type.equals("cheese")) {
  22. this.pizza = new CheesePizza();
  23. }else if (type.equals("greek")) {
  24. this.pizza = new GreekPizza();
  25. }else if (type.equals("pepperoni")) {
  26. this.pizza = new PepperoniPizza();
  27. }
  28. return this.pizza;
  29. }
  30.  
  31. }
  1. package com.ek.factory.simple;
  2.  
  3. import com.ek.factory.Pizza;
  4.  
  5. /**
  6. * @包名 com.ek.factory.simple
  7. * @文件名 PizzaStore.java
  8. * @作者 edi_kai
  9. * @创建日期 2015年8月25日
  10. * @版本 V 1.0
  11. * @描述 这是修改后的PizzaStore
  12. */
  13. public class PizzaStore {
  14.  
  15. SimplePizzaFactory factory;
  16.  
  17. public PizzaStore(SimplePizzaFactory factory) {
  18. super();
  19. this.factory = factory;
  20. }
  21.  
  22. public Pizza orderPizza(String type) {
  23.  
  24. Pizza pizza = this.factory.createPizza(type);
  25.  
  26. pizza.prepare();
  27. pizza.bake();
  28. pizza.cut();
  29. pizza.box();
  30.  
  31. return pizza;
  32. }
  33. }

  这就是一个简单的工厂模式,简单工厂模式其实并不是一个设计模式,更像是一种编程习惯。

  简单工厂模式算是最容易理解的工厂模式了,说完了简单工厂模式,让我们来分别看看它的两个延伸,工厂方法模式和抽象工厂模式。

  在介绍模式之前,我们先来模拟一个需求场景,现在的汽车越来越多,那么汽车是怎么生产的呢?首先,你得有一个汽车生产工厂,然后,确定来生产什么牌子的汽车(国产车,美系车,德国车,韩系车)。不同的牌子需要由对应的工厂来生产汽车。

  1丶工厂方法模式

    定义:定义了一个创建对象的接口,但是由子类来决定实例化的是哪一个对象。工厂方法让类把实例化推迟到了子类中。

    工厂模式对应的类图如下

  类图对应的代码如下:

  1. /**
  2. * Project Name: head first
  3. * File Name: CarFactory.java
  4. * Package Name: com.ek.factory_2
  5. * Reason: 抽象工厂
  6. * Date: 2015年9月7日上午12:19:10
  7. * Copyright (c) 2015, edi_kai All Rights Reserved.
  8. * @author: edi_kai
  9. * @version: v1.1
  10. * @since: JDK 1.7
  11. */
  12. package com.ek.factory_2;
  13.  
  14. import com.ek.factory_2.product.Car;
  15.  
  16. public interface CarFactory {
  17. Car createCar(String type);
  18. }
  1. /**
  2. * Project Name: head first
  3. * File Name: ChineseCarFactory.java
  4. * Package Name: com.ek.factory_2
  5. * Reason: 具体工厂-国产车.
  6. * Date: 2015年9月7日上午12:24:20
  7. * Copyright (c) 2015, edi_kai All Rights Reserved.
  8. * @author: edi_kai
  9. * @version: v1.1
  10. * @since: JDK 1.7
  11. */
  12. package com.ek.factory_2;
  13.  
  14. import com.ek.factory_2.product.Car;
  15. import com.ek.factory_2.product.NormalCarBorui;
  16. import com.ek.factory_2.product.SUVCarBYDsong;
  17.  
  18. public class ChineseCarFactory implements CarFactory {
  19.  
  20. @Override
  21. public Car createCar(String type) {
  22.  
  23. if ("borui".equalsIgnoreCase(type)) {
  24. return new NormalCarBorui();
  25. }else if ("song".equalsIgnoreCase(type)) {
  26. return new SUVCarBYDsong();
  27. }
  28.  
  29. return null;
  30. }
  31.  
  32. }
  1. /**
  2. * Project Name: head first
  3. * File Name: KoreaCarFactory.java
  4. * Package Name: com.ek.factory_2
  5. * Reason: 具体工厂-韩系车.
  6. * Date: 2015年9月7日上午12:28:08
  7. * Copyright (c) 2015, edi_kai All Rights Reserved.
  8. * @author: edi_kai
  9. * @version: v1.1
  10. * @since: JDK 1.7
  11. */
  12. package com.ek.factory_2;
  13.  
  14. import com.ek.factory_2.product.Car;
  15. import com.ek.factory_2.product.NormalCarELartra;
  16. import com.ek.factory_2.product.NormalCarSonata;
  17.  
  18. public class KoreaCarFactory implements CarFactory {
  19.  
  20. @Override
  21. public Car createCar(String type) {
  22.  
  23. if ("sonata".equalsIgnoreCase(type)) {
  24. return new NormalCarSonata();
  25. }else if ("elartra".equalsIgnoreCase(type)) {
  26. return new NormalCarELartra();
  27. }
  28.  
  29. return null;
  30. }
  31.  
  32. }
  1. /**
  2. * Project Name: head first
  3. * File Name: Main.java
  4. * Package Name: com.ek.factory_2.main
  5. * Reason: 测试代码.
  6. * Date: 2015年9月7日上午12:31:42
  7. * Copyright (c) 2015, edi_kai All Rights Reserved.
  8. * @author: edi_kai
  9. * @version: v1.1
  10. * @since: JDK 1.7
  11. */
  12. package com.ek.factory_2.main;
  13.  
  14. import com.ek.factory_2.CarFactory;
  15. import com.ek.factory_2.ChineseCarFactory;
  16. import com.ek.factory_2.KoreaCarFactory;
  17. import com.ek.factory_2.product.Car;
  18.  
  19. public class Main {
  20.  
  21. public static void main(String[] args) {
  22. CarFactory ccf = new ChineseCarFactory();
  23. Car song = ccf.createCar("song");
  24.  
  25. CarFactory kcf = new KoreaCarFactory();
  26. Car sonata = kcf.createCar("sonata");
  27.  
  28. song.getName();
  29. song.getBrand();
  30. song.getColor();
  31.  
  32. sonata.getName();
  33. sonata.getBrand();
  34. sonata.getColor();
  35. }
  36.  
  37. }

    工厂方法模式的特点:

      1)针对统一个产品等级,不存在父子级关系(看一下抽象工厂模式的类图即可明白);

      2)只有一个抽象产品类,所有的产品都实现/继承自该抽象类(Car);

      3)所有的具体产品类按具体的工厂类分类,当需要添加新类别的产品时,只需要添加一个具体工厂类即可(如类图中,Sonata属于韩系车,添加KoreaCarFactory实现    CarFactory即可),易于扩展,并完全符合开闭原则的!;

    工厂方法模式总结:

      工厂方法模式足以应付我们可能遇到的大部分业务需求。但是当产品种类非常多时,就会出现大量的与之对应的工厂类,这不应该是我们所希望的(就如同下面我们要    说的场景)。那么这种情况下就可能需要使用抽象工厂模式了。

  现在需求改变了,不仅需要按照国家来生产汽车,还要按照用途来生产(私家轿车/SUV/MPV/货车);这个需求中汽车出现了多级产品树,如果在继续使用工厂方法模式会有大量的代码,不利于后期维护,所以,这个时候我们就应该想到抽象工厂模式,来解决这个问题。

  2丶抽象工厂模式

    抽象工厂模式定义:抽象一个接口用来创建相关或依赖对象的家族,而不需要明确指定具体类。

    产品族:具体定义我也不是很清楚,但是类图中的NormalCarBorui(吉利博瑞汽车)跟SUVCarBYDsong SUVCarCS75是同一产品族;

    产品树:SUVCcar PMVCar是同一级产品树

    抽象工厂模式的特点:

      1)针对的是面向多个产品等级结构;

      2)一个抽象工厂类,可以派生出多个具体工厂类

      3)相同的产品族对应一个具体工厂,每级产品树中包含几颗树抽象工厂中就会存在几个创建方法;

    总结:

      工厂方法模式适用场景:产品比较单一,只有一级产品树的时候

      抽象工厂模式适用场景:产品比较复杂,存在多级业务品种,业务分类的时候

      再通俗深化理解下:工厂模式针对的是一个产品等级结构 ,抽象工厂模式针对的是面向多个产品等级结构的---看上面工厂方法模式跟抽象工厂模式的类图

  

  设计到的新设计原则:

    依赖倒置原则:尽量依赖抽象,不要依赖具体类

  有错误的地方还请大家指出,大家共同学习,谢谢......

  转载请注明出处

Head First 设计模式 第4章工厂模式的更多相关文章

  1. headfirst设计模式(5)—工厂模式体系分析及抽象工厂模式

    先编一个这么久不写的理由 上周我终于鼓起勇气翻开了headfirst设计模式这本书,看看自己下一个设计模式要写个啥,然后,我终于知道我为啥这么久都没写设计模式了,headfirst的这个抽象工厂模式, ...

  2. java设计模式-----1、简单工厂模式

    简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一.简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,简单来说 ...

  3. Java设计模式(1)工厂模式(Factory模式)

    工厂模式定义:提供创建对象的接口. 为何使用工厂模式 工厂模式是我们最常用的模式了,著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见. 为什么工厂模式是如此常用?因 ...

  4. 设计模式之单例模式与工厂模式的Python实现(二)

    2. 工厂模式 工厂模式是创建型设计模式的一种.核心的思想是,通过传递给类或函数某种产品的信息来创建产品并返回.当我们想得到产品a对象,只需把产品a的名字传递给工厂函数就能得到产品a对象.而核心思想的 ...

  5. [Python编程实战] 第一章 python的创建型设计模式1.1抽象工厂模式

    注:关乎对象的创建方式的设计模式就是“创建型设计模式”(creational design pattern) 1.1 抽象工厂模式 “抽象工厂模式”(Abstract Factory Pattern) ...

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

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

  7. 10月27日PHP加载类、设计模式(单例模式和工厂模式)、面向对象的六大原则

    加载类可以使用include.require.require_once三种中的任意一种,每个关键字都有两种方法,但是这种方法的缺点是需要加载多少个php文件,就要写多少个加载类的方法.一般也就需要加载 ...

  8. Java设计模式2:简单工厂模式

    简单工厂模式 简单工厂模式是类的创建模式,又叫做静态工厂方法模式.简单工厂模式由一个工厂对象决定生产出哪一种产品类的实例. 为什么要使用简单工厂模式 原因很简单:解耦. A对象如果要调用B对象,最简单 ...

  9. C#设计模式之二简单工厂模式(过渡模式)

    一.引言 之所以写这个系列,是了为了自己更好的理解设计模式,也为新手提供一些帮助,我都是用最简单的.最生活化的实例来说明.在上一篇文章中讲解了单例模式,今天就给大家讲一个比较简单的模式--简单工厂模式 ...

随机推荐

  1. centos7 minimal版本下mysql的安装

    最近第一次尝在虚拟机上安装mysql,由于是centos7 minimal版本,很多安装包或命令必须自己添加,遇到很多问题. 首先是执行# yum install mysql-server 报错: 打 ...

  2. Student implements java.io.Serializable

    package JBJADV003; public class Student implements java.io.Serializable { private String name; priva ...

  3. Spring Security4实例(Java config版)——ajax登录,自定义验证

    本文源码请看这里 相关文章: Spring Security4实例(Java config 版) -- Remember-Me 首先添加起步依赖(如果不是springboot项目,自行切换为Sprin ...

  4. Eclipse简单插件开发-启动时间提示

    1.新建Plug-in Project 不用改其他选项,直接点击"Next",然后点击"Finish"   2.新建ShowTime.java package ...

  5. tp框架表单验证 及ajax

    之前的表单验证都是用js写的,这里也可以使用tp框架的验证.但是两者比较而言还是js验证比较好,因为tp框架验证会运行后台代码,这样运行速度和效率就会下降. 自动验证是ThinkPHP模型层提供的一种 ...

  6. linux文件系统及bash基础特性

    linux文件系统 一.根文件系统 linux被识别的第一个被称为根之间关联的文件系统叫做根文件系统(rootfs),其他分区要想被读到,需要挂载到根目录的某个挂载点(根的子目录)上.根文件系统至关重 ...

  7. 【Splay】例题

    营业额统计 题目背景 HNOI2002 DAY2 T2 题目描述 Tiger 最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger 拿出了公司 ...

  8. jmeter 接口重放(投票活动)

    目的 这几天公司弄了个投票的活动,召集大家一起投票.自己比较懒,就想这个投票是不是可以直接抓包进行重放通过jmeter集成到jenkins里面去每天来跑.试了下成功了,这里把对应的方案抛出来. 第一步 ...

  9. (转)Linux端口nmap和netstat命令

    场景:弄不清楚端口和服务的关系,总觉得这个命令很有用但是还不清楚如何使用 1 linux端口与服务 1.1 安全概述 网络传输安全.操作系统安全.应用软件安全构成了整个网络应用的安全:其中应用软件安全 ...

  10. (转)HashMap深入原理解析

    [HashMap]深入原理解析 分类: 数据结构 自考 equals与“==”(可以参考自己的另一篇博文) 1,基本数据类型(byte,short,char,int,long,float,double ...