Header First设计模式学习笔记——工厂模式

一、简单工厂

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

通俗的来讲就是由工厂方法确定一个框架,具体的实现由其子类来完成。与简单工厂相比,简单工厂可是完成了整个对象的创建。

     严格的来说简单工厂并不是一种设计模式,他更像是一种编程习惯。

代码说明一切!

1、这是一个简单工厂

package my.oschina.net.design.factory;

public class SimplePizzaFactory {

	/**
	 * 根据传入的type参数,返回相应的pizza
	 * @param type
	 * @return
	 */
	public Pizza 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();
		} else if (type.equals("veggie")) {
			pizza = new VeggiePizza();
		}
		return pizza;
	}
}

2、这是一个pizza的store

package my.oschina.net.design.factory;

public class PizzaStore {
	//通过组合的使用,加上一个简单工厂SimplePizzaFactory的引用,用于创建pizza
	SimplePizzaFactory factory;
 
	public PizzaStore(SimplePizzaFactory factory) { 
		this.factory = factory;
	}
 
	public Pizza orderPizza(String type) {
		Pizza pizza;
		//调用简单工厂SimplePizzaFactory的createPizza(type)方法创建pizza
		pizza = factory.createPizza(type);
 
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();

		return pizza;
	}
}

    我们可以看到,当我们需要一个pizza时并不需要知道该如何创建具体的pizza,我们只要调用一个简单工厂的方法,工厂就会给我们返回一个pizza,很炫酷!(更深一步,我们可以加入第一个模式——策略模式,也就是说可以动态的设置不同的简单工厂,从而让简单工厂返回不同的pizza)

    其实,大家在写代码的时候都或多或少的用到过这个code习惯。比如说在写一些项目的时候,我们会额外加一个叫作utils的包,里面基本上都是一些类的静态方法或者叫做工具函数(像一些提取特定字符串啊等)。这其实就是静态工厂(我们不需要创建对象就可以通过其类名调用想用的工具函数),而与普通的简单工厂相比,他不能通过继承改变创建对象的行为。

二、工厂方法模式

    看完简单工厂,你可能会说,哟,不错哦!那我们为什么还要使用工厂方法模式呢?

    仔细想想,假如我们又出新产品了,不仅有cheese, peperoni, clam, vegie的pizza还有什么白菜,萝卜,西瓜pizza,意思就是说我们的产品可是变化着的,那问题来了,我们会不可避免的修改代码,什么?修改类的代码!那就不好了!head first 曾提及过一个原则叫做开放关闭原则,大概的意思是说,类应该对扩展开放(你可以通过继承来扩展这个类),而对修改关闭(你要是想要修改我这个类,我就不愿意了)。

    很明显啊!简单工厂要想实现产品的更新工作,就必须要违反这个原则!那肿么办呢?好吧,来看看工厂方法模式。

来看看我们新的PizzaStore(这是一个abstract类,不能创建这个类的对象)

package my.oschina.net.design.factory;
/**
 * 这是一个抽象类,通过继承实现createPizza方法,
 * 我们可以创建不同的对象
 * @author Eswin
 *
 */
public abstract class PizzaStore {
 
	//这里定义一个工厂方法
	abstract Pizza createPizza(String item);
 
	public Pizza orderPizza(String type) {
	
		Pizza pizza = createPizza(type);
		
		System.out.println("--- Making a " + pizza.getName() + " ---");
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();
		
		return pizza;
	}
}

再来看两个他的子类(通过继承我们实现了超类代码和子类创建对象的代码的解耦)

package my.oschina.net.design.factory;

public class ChicagoPizzaStore extends PizzaStore {

	Pizza createPizza(String item) {
        	if (item.equals("cheese")) {
            		return new ChicagoStyleCheesePizza();
        	} else if (item.equals("veggie")) {
        	    	return new ChicagoStyleVeggiePizza();
        	} else if (item.equals("clam")) {
        	    	return new ChicagoStyleClamPizza();
        	} else if (item.equals("pepperoni")) {
            		return new ChicagoStylePepperoniPizza();
        	} else return null;
	}
}


package my.oschina.net.design.factory;

public class NYPizzaStore extends PizzaStore {

	Pizza createPizza(String item) {
		if (item.equals("cheese")) {
			return new NYStyleCheesePizza();
		} else if (item.equals("veggie")) {
			return new NYStyleVeggiePizza();
		} else if (item.equals("clam")) {
			return new NYStyleClamPizza();
		} else if (item.equals("pepperoni")) {
			return new NYStylePepperoniPizza();
		} else return null;
	}
}

检验代码

package my.oschina.net.design.factory;

public class PizzaTestDrive {
 
	public static void main(String[] args) {
		PizzaStore nyStore = new NYPizzaStore();
		PizzaStore chicagoStore = new ChicagoPizzaStore();
 
		Pizza pizza = nyStore.orderPizza("cheese");
		System.out.println("Ethan ordered a " + pizza.getName() + "\n");
 
		pizza = chicagoStore.orderPizza("cheese");
		System.out.println("Joel ordered a " + pizza.getName() + "\n");

		pizza = nyStore.orderPizza("clam");
		System.out.println("Ethan ordered a " + pizza.getName() + "\n");
 
		pizza = chicagoStore.orderPizza("clam");
		System.out.println("Joel ordered a " + pizza.getName() + "\n");
	}
}

这样,我们通过不同的store(不同的子类)相同的orderPizza方法就可以创造出不同的pizza!

三、抽象工厂

定义:提供一个接口,用于创建一组相关的或者相依赖的的家族,而不需明确指明具体类。

在我理解就是纯粹的工厂方法的叠加,他提供一个创建一系列相关联的一组对象的接口,由实现这个接口的类来具体实现各个对象的创建工作

先来定义一个接口PizzaIngredientFactory,他定义了一系列的创建Pizza材料的方法

package my.oschina.net.design.abstract_actory;

public interface PizzaIngredientFactory {
 
	public Dough createDough();
	public Sauce createSauce();
	public Cheese createCheese();
	public Veggies[] createVeggies();
	public Pepperoni createPepperoni();
	public Clams createClam();
 
}

看他的两个子类(准确的说是实现了这个接口的类)

package my.oschina.net.design.abstract_actory;

public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
 
	public Dough createDough() {
		return new ThinCrustDough();
	}
 
	public Sauce createSauce() {
		return new MarinaraSauce();
	}
 
	public Cheese createCheese() {
		return new ReggianoCheese();
	}
 
	public Veggies[] createVeggies() {
		Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() };
		return veggies;
	}
 
	public Pepperoni createPepperoni() {
		return new SlicedPepperoni();
	}

	public Clams createClam() {
		return new FreshClams();
	}
}

package my.oschina.net.design.abstract_actory;

public class ChicagoPizzaIngredientFactory 
	implements PizzaIngredientFactory 
{

	public Dough createDough() {
		return new ThickCrustDough();
	}

	public Sauce createSauce() {
		return new PlumTomatoSauce();
	}

	public Cheese createCheese() {
		return new MozzarellaCheese();
	}

	public Veggies[] createVeggies() {
		Veggies veggies[] = { new BlackOlives(),  new Spinach(), new Eggplant() };
		return veggies;
	}

	public Pepperoni createPepperoni() {
		return new SlicedPepperoni();
	}

	public Clams createClam() {
		return new FrozenClams();
	}
}

看看我们的CheesePizza类和ClamPizza类的创建

package my.oschina.net.design.abstract_actory;

public class CheesePizza extends Pizza {
	//这里组合了一个PizzaIngredientFactory对象的引用,用于提供不同的原料
	PizzaIngredientFactory ingredientFactory;
 
	/**
	 * 通过传入一个PizzaIngredientFactory原料工厂,我们可以在制作Pizza的时候动态的产生所需要的原料
	 * @param ingredientFactory
	 */
	
	public CheesePizza(PizzaIngredientFactory ingredientFactory) {
		this.ingredientFactory = ingredientFactory;
	}
 
	void prepare() {
		System.out.println("Preparing " + name);
		dough = ingredientFactory.createDough();
		sauce = ingredientFactory.createSauce();
		cheese = ingredientFactory.createCheese();
	}
}

package my.oschina.net.design.abstract_actory;

public class ClamPizza extends Pizza {
	PizzaIngredientFactory ingredientFactory;
 
	public ClamPizza(PizzaIngredientFactory ingredientFactory) {
		this.ingredientFactory = ingredientFactory;
	}
 
	void prepare() {
		System.out.println("Preparing " + name);
		dough = ingredientFactory.createDough();
		sauce = ingredientFactory.createSauce();
		cheese = ingredientFactory.createCheese();
		clam = ingredientFactory.createClam();
	}
}

再来看看改进后的NYPPizzaStore

package my.oschina.net.design.abstract_actory;

public class NYPizzaStore extends PizzaStore {
 
	protected Pizza createPizza(String item) {
		Pizza pizza = null;
		PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
 
		if (item.equals("cheese")) {
  
			pizza = new CheesePizza(ingredientFactory);
			pizza.setName("New York Style Cheese Pizza");
  
		} else if (item.equals("veggie")) {
 
			pizza = new VeggiePizza(ingredientFactory);
			pizza.setName("New York Style Veggie Pizza");
 
		} else if (item.equals("clam")) {
 
			pizza = new ClamPizza(ingredientFactory);
			pizza.setName("New York Style Clam Pizza");
 
		} else if (item.equals("pepperoni")) {

			pizza = new PepperoniPizza(ingredientFactory);
			pizza.setName("New York Style Pepperoni Pizza");
 
		} 
		return pizza;
	}
}

对于此时的NYPPizzaStore,创建具体的Pizza的时候我们就要传入一个PizzaIngredientFactory对象了!

四、三者的比较

对于简单工厂,所有的对象的创建由简单工厂全权负责,只要最后可以给我们返回一个我们需要的对象就可以了,他的运用是通过组合的方式实现的

对于工厂方法,抽象的父类提供一个对象创建的接口,具体对象的创建推迟到子类中去实现,从而实现扩展;

对于抽象工厂,可以看成是工厂方法的叠加,他提供了创建一系列相关的对象的接口,由各个子类去实现,他的运用也是通过组合的方式实现的。


转载于:https://my.oschina.net/v5871314/blog/282981

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值