本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/41085085

昨天看完了工厂模式,觉得在开发的过程中好多地方都能够使用工厂模式,但是很多时候却都没有去使用。我觉得一方面可能是偷懒,懒得去思考,懒得去设计接口;另一方面可能是只为了眼前的需求,觉得开发的产品能使用就行,而不管其后续的维护以及更新。这两个方面长期下去,对自己的提升没有什么好处。其实我自己就是属于第二类,只为了眼前的需求而不去思考后续的维护和更新。可能是刚工作不久,没有那么好的技术,我想我会慢慢转变自己,能够写出漂亮的代码。闲话不多说了,下面分享工厂模式的一些学习总结。

我们一般创建对象都喜欢new一个,因为比较方便;但是我们在使用new的时候,是在实例化一个具体的类,代码绑定了具体的类会导致代码比较脆弱,缺乏弹性;当类发生变化时,涉及到该类的地方都必须修改代码,这样会导致代码一团糟。

假设我们有一家面包店BreadStore,刚开业的时候,只提供一种面包,当需要订购面包的时候,代码可能会这样写:

	Bread orderBread(){
		Bread bread = new Bread();

		bread.prepare();
		bread.bake();
		bread.cut();
		bread.box();
		return bread;

	}

随着时间的推移,需求变大了,有的人想吃玉米面包,有的人想吃豆沙面包,还有的人想吃巧克力面包......,此时代码可能又变成这样了:

	Bread orderBread(String type){
		Bread bread;

		if("corn".equals(type)){
			bread = new CornBread();
		} else if("beanpaste".equals(type)){
			bread = new BeanpasteBread();
		} else if("chocolate".equals(type)){
			bread = new ChocolateBread();
		}

		bread.prepare();
		bread.bake();
		bread.cut();
		bread.box();
		return bread;

	}

又过了一段时间,附近开了好多家面包店,竞争激烈,你发现竞争者的菜单中多了一些流行风味的面包,比如欧洲面包、荞麦面包,而最近玉米面包又卖的不好,我们决定将其从菜单上撤销,此时的代码又变成这样了:

	Bread orderBread(String type){
		Bread bread;

		if(<span style="color:#cc0000;">"corn".equals(type</span>)){
			<span style="color:#ff0000;">bread = new CornBread()</span>;
		} else if("beanpaste".equals(type)){
			bread = new BeanpasteBread();
		} else if("chocolate".equals(type)){
			bread = new ChocolateBread();
		} <span style="color:#cc33cc;">else if("Europe".equals(type)</span>){
			<span style="color:#cc33cc;">bread = new EuropeBread()</span>;
		} <span style="color:#cc33cc;">else if("Buckwheat".equals(type)</span>){
			<span style="color:#cc33cc;">bread = new BuckwheatBread()</span>;
		}

		bread.prepare();
		bread.bake();
		bread.cut();
		bread.box();
		return bread;

	}

我们可以看出,只要随着时间的改变,if...else...里面的需求总是在变化,当我们依赖了具体变化的类时,代码将变得特别难以维护,此时,我们应该考虑到抽象。另外,我们注意到,return上面的四行代码是不想改变的地方,其包含了面包的准备、烘烤、包装,这些流程多年都没有变化,此时可使用封装,将不变的部分封装起来。

首先,我们把创建Bread对象的代码从orderBread()方法中抽离出来,然后把该代码转移到另外一个新对象中,新对象只管如何创建面包。任何时候需要创建面包,就找它。我们也称该对象为“工厂”。这里,我们创建一个简单的面包工厂SimpleBreadFactory,而orderBread()就成为了该工厂的客户。当需要面包的时候,就叫面包工厂做一个出来。现在,orderBread()方法只关心从工厂得到一个面包,而此时的面包实现了抽象的Bread接口,而Bread接口提供了prepare()、bake()、cut()、box()方法来进行相应操作。抽象Bread和创建的简单工厂的代码如下:

	public abstract class Bread {

		void prepare(){
			System.out.println("prepare for...");
		}

		void bake() {
			System.out.println("Bake for 25 minutes at 350");
		}

		void cut() {
			System.out.println("Cutting the pizza into diagonal slices");
		}

		void box() {
			System.out.println("Place pizza in official PizzaStore box");
		}

	}
	public class SimpleBreadFactory(){
		public Bread() creatBread(String type){
			Bread bread = null;

			if("corn".equals(type)){
				bread = new CornBread();
			} else if("beanpaste".equals(type)){
				bread = new BeanpasteBread();
			} else if("chocolate".equals(type)){
				bread = new ChocolateBread();
			} 

			return bread;
		}
	}

现在,我们可以重新构造BreadStore了,我们要做的就是依靠工厂来为我们创建面包,代码如下:

	public class BreadStore{
		SimpleBreadFactory factory;

		public BreadStore(SimpleBreadFactory factory){
			this.factory = factory;
		}

		public Bread orderBread(String type){
			Bread bread; /**未抽象之前的Bread**/

			bread = factory.creatBread(type);
			bread.prepare();
			bread.bake();
			bread.cut();
			bread.box();
			return bread;
		}
	}

在上面的代码中,我们为BreadStore加上了对简单面包工厂的引用;在BreadStore是构造器中需要传入一个工厂作为参数;在orderBread()方法中通过简单传入订单类型来使用工厂创建面包,在这里面我们把new操作符替换为工厂对象创建方法,不再使用具体实例化。

若干年后,面包店经营的不错,很多地方的消费者都希望面包店能够在当地有加盟店,此时,简单面包工厂已经不能满足需求了,加盟店都希望有适合当地需求的面包工厂,这样就产生了类似BJBreadFactory、TJBreadFactory、SHBreadFactory的面包工厂。

	BJBreadFactory bjFactory = new BJBreadFactory();
	BreadStore bjStore = new BreadStore(bjFactory);
	bjStore.orderBread("bjtaste");

	TJBreadFactory tjFactory = new TJBreadFactory();
	BreadStore tjStore = new BreadStore(tjFactory);
	tjStore.orderBread("bjtaste");

	SHBreadFactory shFactory = new SHBreadFactory();
	BreadStore shStore = new BreadStore(shFactory);
	shStore.orderBread("bjtaste");

考虑到让面包制作局限于BreadStore,同时又能够让加盟店仍然可以自由制作该区的面包,这样就允许子类做决定了。我们将BreadStore抽象出来。

	public abstract class BreadStore{
		abstract Bread creatBread(String type);

		public Bread orderBread(String type){
			Bread bread; /**未抽象之前的Bread**/

			bread = factory.creatBread(type);
			bread.prepare();
			bread.bake();
			bread.cut();
			bread.box();
			return bread;
		}
	}

对于BreadStore的子类,每一个都会覆盖createBread()方法,同时又使用BreadStore中的orderBread()方法,其实也可将orderBread()声明为final,以防止被子类覆盖。这样,不同地区的加盟店都可以创建需要的面包了。

我们在武汉开一家新的面包店:

	public class WHBreadStore extends BreadStore{
		Bread creatBread(String item){
			if("corn".equals(item)){
				bread = new WHCornBread();
			} else if("beanpaste".equals(item)){
				bread = new WHBeanpasteBread();
			} else if("chocolate".equals(item)){
				bread = new WHChocolateBread();
			} else return null;
		}
	}

通过声明工厂方法 ,我们可以看出:原来是由一个对象负责所有具体类的实例化,现在我们对BreadStore做了一些调整,变成了由一群子类来负责实例化。

对于 abstract Product factoryMethod(String type)工厂方法:

(1)工厂方法是抽象的,所以需要依赖子类来处理对象的创建。

(2)工厂方法必须返回一个产品。在超类中定义的方法,通常会用到工厂方法的返回值。

(3)工厂方法将客户(超类中的代码,如orderBread()和实际创建具体产品的代码分离开来)。

最后,我们再来认识一下工厂方法模式:所有的工厂模式都是用来封装对象的创建,这样就减小了耦合。它是通过让子类来决定该创建的对象是什么,从而来达到将对象创建的过程封装的目的。下面两张图反映了创建者类和产品类之间的关系:

设计模式之——工厂模式(A)的更多相关文章

  1. 设计模式——抽象工厂模式及java实现

    设计模式--抽象工厂模式及java实现 设计模式在大型软件工程中很重要,软件工程中采用了优秀的设计模式有利于代码维护,方便日后更改和添加功能. 设计模式有很多,而且也随着时间在不断增多,其中最著名的是 ...

  2. 5. 星际争霸之php设计模式--抽象工厂模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  3. 3. 星际争霸之php设计模式--简单工厂模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  4. iOS 设计模式之工厂模式

    iOS 设计模式之工厂模式 分类: 设计模式2014-02-10 18:05 11020人阅读 评论(2) 收藏 举报 ios设计模式 工厂模式我的理解是:他就是为了创建对象的 创建对象的时候,我们一 ...

  5. 设计模式之工厂模式(Factory)

    设计模式的工厂模式一共有三种:简单工厂模式,工厂模式,抽象工厂模式 简单工厂模式原理:只有一个工厂类,通过传参的形式确定所创建的产品对象种类 代码如下: #include <stdio.h> ...

  6. php设计模式:工厂模式

    php设计模式:工厂模式 意图: 定义一个用于创建对象的接口,让子类决定实例化哪一个类. 工厂模式实现: 工厂模式中任何创建对象的工厂类都要实现这个接口,实现接口的方法体中都要实现接口中的方法,它声明 ...

  7. 浅析JAVA设计模式之工厂模式(一)

    1 工厂模式简单介绍 工厂模式的定义:简单地说,用来实例化对象,取代new操作. 工厂模式专门负责将大量有共同接口的类实例化.工作模式能够动态决定将哪一个类实例化.不用先知道每次要实例化哪一个类. 工 ...

  8. java 设计模式之工厂模式与反射的结合

    工厂模式: /**  * @author Rollen-Holt 设计模式之 工厂模式  */   interface fruit{     public abstract void eat(); } ...

  9. C#学习之设计模式:工厂模式

    最近研究一下设计模式中工厂模式的应用,在此记录如下: 什么是工厂模式? 工厂模式属于设计模式中的创造型设计模式的一种.它的主要作用是协助我们创建对象,为创建对象提供最佳的方式.减少代码中的耦合程度,方 ...

  10. [JS设计模式]:工厂模式(3)

    简单工厂模式是由一个方法来决定到底要创建哪个类的实例, 而这些实例经常都拥有相同的接口. 这种模式主要用在所实例化的类型在编译期并不能确定, 而是在执行期决定的情况. 说的通俗点,就像公司茶水间的饮料 ...

随机推荐

  1. springboot解决跨域问题(Cors)

    1.对于前后端分离的项目来说,如果前端项目与后端项目部署在两个不同的域下,那么势必会引起跨域问题的出现. 针对跨域问题,我们可能第一个想到的解决方案就是jsonp,并且以前处理跨域问题我基本也是这么处 ...

  2. textarea不能使用maxlength

    知道文本框有个maxlength属性,有次开发项目中使用了textarea标签,没去看文档,直接加了maxlength属性,且有效果没有报错,喜滋滋的用了,结果没两天就测试出了bug 问题描述:文本域 ...

  3. ubuntu14.04 python2.7 安装配置OpenCV3.0

    环境:ubuntu14.04  python2.7 内容:安装并配置OpenCV3.0 今天按照OpenCV官网上的步骤装了OpenCV但是,装好之后python提示“No module named ...

  4. .NET中的各种池

    在.NET中,常用到的池有四个:字符串拘留池.线程池 .应用程序池.数据库连接池. 字符串拘留池 在.NET中字符串是不可变对象,修改字符串变量的值会产生新的对象.为降低性能消耗及减小程序集大小,.N ...

  5. leetcode刷题笔记08 字符串转整数 (atoi)

    题目描述 实现 atoi,将字符串转为整数. 在找到第一个非空字符之前,需要移除掉字符串中的空格字符.如果第一个非空字符是正号或负号,选取该符号,并将其与后面尽可能多的连续的数字组合起来,这部分字符即 ...

  6. MySQL系列教程(四)

    文件打开数(open_files) 我们现在处理MySQL故障时,发现当Open_files大于open_files_limit值时,MySQL数据库就会发生卡住的现象,导致Nginx服务器打不开相应 ...

  7. 好久没有写BLOG了,人老了就开始变懒了【非技术】

    算算到今天,在码农的路上已经走了15年了.马上就40不惑的我,现在是充满的疑惑.

  8. Lua语言模型 与 Redis应用

    Lua语言模型 与 Redis应用 标签: Java与NoSQL 从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis. 本篇博客主要介绍了 Lua 语言不一样的设计 ...

  9. 深度学习与计算机视觉系列(2)_图像分类与KNN

    作者: 寒小阳 &&龙心尘 时间:2015年11月. 出处: http://blog.csdn.net/han_xiaoyang/article/details/49949535 ht ...

  10. Retrofit,Okhttp对每个Request统一动态添加header和参数(五)

    文/Tamic 地址:http://blog.csdn.net/sk719887916/article/details/52189602 Header How to Add header to Eve ...