【张六儿大话设计模式】——简单工厂模式、工厂方法模式、抽象工厂模式

    工厂模式是设计模式中的一种十分重要的创建型模式,工厂模式又分为简单工厂模式、抽象工厂模式以及工厂方法模式。下面来讨论这几种工厂模式。

一、简单工厂模式

    张六儿是一个很会做饭的人,他的女朋友小西十分喜欢吃猪蹄。猪蹄有很多种做法,比如:焖猪蹄、烤猪蹄、卤猪蹄......(不说了,有点饿)但是在小西第一次跟张六儿说她想吃某种做法的猪蹄时,首先要说明白自己喜欢吃什么样的口味,比如焖猪蹄多放点糖做成甜口,烤猪蹄多放点辣椒,卤猪蹄多加点酱油颜色红一点......(要求真高)这样一来,以后每当小西想要吃猪蹄的时候,只要说:“老公,给我做焖/卤/烤猪蹄~”,张六儿就立马知道要把猪蹄做成什么样子,而不需要小西每次都把自己的需求讲一遍,小西只需要关注自己想吃什么猪蹄,而不用关心猪蹄的具体制作过程了~

    上面的过程就是简单工厂模式,张六儿是一个工厂,不同的猪蹄是工厂的产品,消费者小西只需要向工厂发出需要什么样的产品的请求,然后接受产品就可以了。但是这种模式有几个缺点:

    1.当小西想要吃一种新做法的猪蹄的时候,必须要买一个已经做好的猪蹄,然后再让张六儿根据这个猪蹄学会它的做法,并记在自己的脑子中。(扩展性差,需要先创建一个新的产品类,并且要在工厂类中修改相应方法——违反了开闭原则)

    2.如果小西想要吃的三种猪蹄有自己的独特的额外配料(比如焖猪蹄要加黄豆,卤猪蹄的同时卤点鸡蛋),那么张六儿会拒绝(太麻烦啦)。(当不同的产品需要不同的额外参数的时候,简单工厂模式不支持)

//抽象类猪蹄
public abstract class ZhuTi {
	public abstract void cook();
}
//烤猪蹄产品类
public class KaoZhuTi extends ZhuTi{
	@Override
	public void cook() {
		System.out.println("张六儿做了一份烤猪蹄~");
	}
}
public class LuZhuTi extends ZhuTi{
	@Override
	public void cook() {
		System.out.println("张六儿做了一份卤猪蹄~");
	}
}
public class MenZhuTi extends ZhuTi{
	@Override
	public void cook() {
		System.out.println("张六儿做了一份焖猪蹄~");
	}
}
//简单工厂,张六儿
public class Zhang6er {
	public static final int TYPE_M = 1;
	public static final int TYPE_K = 2;
	public static final int TYPE_L = 3;
	
	public static ZhuTi createZhuTi(int type) {
		switch(type) {
		    case 1:
			    return new MenZhuTi();
		    case 2:
		    	    return new KaoZhuTi();
		    case 3:
		    	default:
		    		return new LuZhuTi();	
		}
	}
}
public class Run {
	public static void main(String args[]) {
		ZhuTi zhuti = Zhang6er.createZhuTi(Zhang6er.TYPE_K);
		zhuti.cook();
	}
}

二、工厂方法模式

    上面的简单工程模式的缺点中,我们提到了它违反了开闭原则(对扩展开放,对修改关闭),而工厂方法模式可以很好的解决这个问题。

    张六儿虽然是个好厨子,这一辈子不可能只做这三种猪蹄,但是每次遇到新做法或者其他菜的时候,张六儿都必须学会做并且将它记在脑子里(对工厂类修改,违反开闭原则),这是一件很难的事情。于是张六儿想了一个办法,买了很多的小本子,每次学会一种新做法或是一道新菜,就把这道菜的做法记录在一个本子上。也就是说,每次当小西点菜的时候,张六儿只需要找到对应的本子,然后照着本子上的做法做菜就可以了。这时候张六儿相当于一个抽象工厂,而每个记录菜谱的本子就相当于生产每种具体产品的工厂实例,这样就可以在不违反开闭原则的情况下实现工厂模式啦~

ps:产品类与上例相同

//工厂变为抽象类,只提供制作猪蹄抽象方法
public abstract class Zhang6er {
	public abstract ZhuTi createZhuTi();
}
//专门生产烤猪蹄的工厂
public class Zhang6erK extends Zhang6er{
	@Override
	public ZhuTi createZhuTi() {
		return new KaoZhuTi();
	}

}
public class Zhang6erM extends Zhang6er{
	@Override
	public ZhuTi createZhuTi() {
		return new MenZhuTi();
	}

}
//不需要通过判断参数决定应该生产什么产品,直接创建相应工厂
public class Run {
	public static void main(String args[]) {
		ZhuTi zhuti = new Zhang6erM().createZhuTi();
		zhuti.cook();
	}
}

缺点:

    1.添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;

     2.虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;

     3.一个具体工厂只能创建一种具体产品

三、抽象工厂模式

    工厂方法模式虽然解决了简单工厂模式存在的问题,对于增加新产品时只需要增加新的类继承自抽象工厂类,而不用修改原有的代码。但是,我们希望一个具体的工厂不仅仅能生产单一的产品(只做猪蹄),还希望它能够生产一些别的东西(甜品和饮品)。这就要引入抽象工厂模式的概念了。

    在解释抽象工厂模式之前,先来说一下产品等级结构与产品族的概念:

    1.产品等级结构:产品等级结构即产品的继承结构,如:手机->小米手机、三星手机、OPPO手机。

    2.产品族:产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品:Apple公司->iphone(手机)、iwatch(手表)、macbook(电脑)。

    张六儿不满足于只做一个简简单单的厨子,他对自己要求很高,立志学会世界各国的不同菜系。于是他买了一些菜谱,有中餐菜谱、法餐菜谱、日料菜谱......每个菜谱里面都有主菜、饮品、甜品等等。以后张六儿想学新菜的话可以继续买新的菜谱比如泰国菜谱(实现工厂接口),或者在中餐/法餐/...菜谱后面加一些菜谱上没有的菜的做法(实现做菜接口)就可以了,而不需要记在脑子里每道菜的做法。这样当小西想要吃法餐的时候,张六就可以拿出法餐的菜谱,给小西做一个包括红酒焗羊排、蓝莓气泡水、舒芙蕾在内的套餐啦~

    我们可以把抽象工厂想象成:一个产品可以继续进行细分,它需要各种子产品组装而成。而每类子产品都对应一个相应的抽象产品(如主菜类、甜品类),这些子产品共同构成一个产品(套餐)。这样我们在实现工厂接口时就创建了一个产品族(如法餐、中餐),我们就可以通过一个工厂生产属于同一个产品族下的多个产品(如果用工厂方法模式则需要创建更多的类)。

//三种食物接口
public interface TianPin {
	void cookTP();
}
public interface YinPin {
	void cookYP();
}
public interface ZhuCai {
	void cookZC();
}
//实现类
public class Beef implements ZhuCai{
	@Override
	public void cookZC() {
		System.out.println("牛排");
	}
}
public class FriedRice implements ZhuCai{
	@Override
	public void cookZC() {
		System.out.println("炒饭");
	}
}
public class Juice implements YinPin{
	@Override
	public void cookYP() {
		System.out.println("果汁");
	}
}
public class Coffee implements YinPin{
	@Override
	public void cookYP() {
		System.out.println("咖啡");
	}
}
public class PumpkinPie implements TianPin{
	@Override
	public void cookTP() {
		System.out.println("南瓜饼");
	}
}
public class Souffle implements TianPin{
	@Override
	public void cookTP() {
		System.out.println("舒芙蕾");
	}
}
//套餐工厂
public abstract class AbstractFactory {
	public abstract ZhuCai cookZhuCai();
	public abstract TianPin cookTianPin();
	public abstract YinPin cookYinPin();
}
public class ChineseMeal extends AbstractFactory{
	@Override
	public TianPin cookTianPin() {
		return new PumpkinPie();
	}
	@Override
	public ZhuCai cookZhuCai() {
		return new FriedRice();
	}
	@Override
	public YinPin cookYinPin() {
		return new Juice();
	}	
}
public class FranchMeal extends AbstractFactory{
	@Override
	public ZhuCai cookZhuCai() {
		return new Beef();
	}
	@Override
	public TianPin cookTianPin() {
		return new Souffle();
	}
	@Override
	public YinPin cookYinPin() {
		return new Coffee();
	}
}
public class Main {
	public static void main(String args[]) {
		AbstractFactory chineseMeal = new ChineseMeal();
		TianPin tianPin = chineseMeal.cookTianPin();
		YinPin yinPin = chineseMeal.cookYinPin();
		ZhuCai zhuCai = chineseMeal.cookZhuCai();
		zhuCai.cookZC();
		yinPin.cookYP();
		tianPin.cookTP();
	}
}

    优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象,产品等级结构易扩展(买一本新的菜谱)。

    缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的类里面加代码(添加菜谱中的新分类,如小吃类、下午茶类)。


你可能感兴趣的:(设计模式,张六儿大话设计模式)