设计模式之四 工厂模式(简单工厂、工厂方法、抽象工厂)

  • 工厂模式

定义

简单工厂其实并不是一个设计模式,反而比较像是一种编程习惯。有些开发人员把这个编程习惯误认为是“工厂模式”(Factory Pattern)。

所有工厂模式都用来封装对象的创建。工厂方法模式(Factory Method Pattern)通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。

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

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

优缺点

应用场景

例子

Pizza店的简单工厂类

public class SimplePizzaFactory {
	public SimplePizzaFactory createPizza(String type) {
		Pizza pizza = null;
		
		if(type.equals("cheese" )) {
			pizza = new CheesePizza();
		} else if(type.equals("pepperoni" )) {
			pizza = new PepperoniPizza();
		} else if(type.equals("clam" )) {
			pizza = new ClamPizza();
		}
		return pizza;
	}
}

使用简单工厂的PizzaStore类

public class PizzaStore {
	SimplePizzaFactory factory;
	
	public PizzaStore(SimplePizzaFactory factory) {
		this.factory = factory;
	}
	
	public Pizza orderPizza(String type) {
		Pizza pizza;
		
		pizza = factory.createPizza(type);
		
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		
		return pizza;
	}
	
}

 

针对不同地区加盟店的披萨具有特色的风味,下面把PizzaStore改为超类,每个域类型继承这个PizzaStore,每个子类各自决定如何制造披萨。

public abstract class PizzaStore {
//	SimplePizzaFactory factory;
//	
//	public PizzaStore(SimplePizzaFactory factory) {
//		this.factory = factory;
//	}
	
	public Pizza orderPizza(String type) {
		Pizza pizza;
		
		pizza = createPizza(type);
		
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		
		return pizza;
	}
	
	abstract Pizza createPizza(String type);
}

 

下面尝试无锡风味的加盟店:

public class WXPizzaStore extends PizzaStore {

	@Override
	Pizza createPizza(String type) {
		if(type.equals("cheese" )) {
			return new WXStyleCheesePizza();
		} else if(type.equals("pepperoni" )) {
			return new WXStylePepperoniPizza();
		} else if(type.equals("clam" )) {
			return new WXStyleClamPizza();
		}
		
		return null;
	}
}

 

原本是由一个对象(SimplePizzaFactory)负责所有具体类的实例化,现在对PizzaStore做些小改变,变成由一群子类负责实例化;现在,实例化披萨的责任被移到一个“方法”中,此方法就如同是一个“工厂”。

abstract Pizza createPizza(String type);

工厂方法负责处理对象的创建,并将这样的行为封装在子类中。这样,客户程序中关于超类的代码就和子类对象创建代码解耦了。

abstract Product factoryMethod(String type);

 

抽象工厂模式(工厂接口)客户从具体的产品中解耦

现在需要解决加盟店的原料问题,为了保证产品的品质,加盟店必须从工厂获取原料。

public abstract class Pizza {

	String name;
	Dough dough;
	Sauce sauce;
	Veggies[] veggies;
	Cheese cheese;
	Pepperoni pepperoni;
	Clams clam;
	
	abstract void prepare();
	
	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");
	}
	
	String getName() {
		return name;
	}
	
	void setName(String name) {
		this.name = name;
	}
	
	@Override
	public String toString() {
		return "Pizza [name=" + name + "]";
	}
} 

 

不同风味的Pizza使用原料工厂来获取原料。

public class CheesePizza extends Pizza {

	PizzaIngredientFactory ingredientFactory;//原料工厂
	
	public CheesePizza(PizzaIngredientFactory ingredientFactory) {
		this.ingredientFactory = ingredientFactory;
	}
	@Override
	void prepare() {
		System.out.println("Preparing " + name);
		dough = ingredientFactory.createDough();
		sauce = ingredientFactory.createSauce();
		cheese = ingredientFactory.createCheese();
	}
}

 

哈喇披萨:

public class ClamPizza extends Pizza {



    PizzaIngredientFactory ingredientFactory;//原料工厂

   

    public ClamPizza(PizzaIngredientFactory ingredientFactory) {

       this.ingredientFactory = ingredientFactory;

    }

    @Override

    void prepare() {

       System.out.println("Preparing " + name);

       dough = ingredientFactory.createDough();

       sauce = ingredientFactory.createSauce();

       clam = ingredientFactory.createClam();

    }

}

 

设计原则

找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。

要依赖抽象,不要依赖具体类(依赖倒置原则)。(不能让高层组件依赖底层组件)

多用组合,少用继承。

针对接口编程,不针对实现编程。

为交互对象之间的松耦合设计而努力。

类应该对扩展开放,对修改关闭,

 

小结

所有工厂模式都用来封装对象的创建。工厂方法模式(Factory Method Pattern)通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。

本图摘自《Head First 设计模式》一文,如有侵权,请联系博主删除

 

小知识

依赖倒置:所谓依赖倒置原则,就是不论高层组件和低层组件都应该依赖于抽象,而不是具体实现类。听起来更像是针对接口编程,而不是针对实现编程,但是这里依赖倒置原则更强调抽象的概念,不要让高层组件依赖低层组件,更不能依赖具体实现类,都要依赖于抽象。依赖倒置原则的核心在于面向接口编程,目的在于解耦

在面向过程中,往往是高层组件调用低层组件,这样,高层组件就会依赖于低层组件,当低层组件发生剧烈变动时,高层组件也要跟着变动,就会倒置模块的复用性大大降低,并且大大提高开发成本,增加了软件扩展、维护的复杂度。如下为面向过程的软件开发调用图:

(图片摘自:https://blog.csdn.net/fightfaith/article/details/49556053 如有侵权,联系博主删除)

由图可以看出,高层组件调用低层组件,即高层组件依赖于低层组件,当低层组件发生变化时,势必会对高层组件产生影响。

那么我们应该怎样改变这种情况呢?应用依赖倒转原则可以解决这个问题,即面向接口编程。让我们的程序依赖于抽象,实现的细节也依赖于抽象。即使实现细节不断变动,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序与实现细节之间的耦合度。面向接口示意图如下:

(图片摘自:https://blog.csdn.net/fightfaith/article/details/49556053 如有侵权,联系博主删除)

这样,无论低层组件怎样变化,只要抽象组件不发生变化,高层组件就不会发生变化,实现了客户程序与实现细节的解耦

下面的指导方针,能帮你避免在OO设计中违反依赖倒置原则:

变量不可以持有具体类的引用。(如果使用new,就会持有具体类的引用。 你可以改用工厂来避开这样的做法)

不要让类派生自具体类。(如果派生自具体类,你就会依赖具体类。请派生自一个抽象(接口或抽象类))

不要覆盖基类中已实现的方法。(如果覆盖基类中已实现的方法。那么你的基类就不是一个真正适合被继承的抽象。基类中已实现的方法,应该由所有的子类共享)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值