zoukankan      html  css  js  c++  java
  • 【设计模式】学习笔记6:抽象工厂模式



    本文出自   http://blog.csdn.net/shuangde800



    ——所有工厂都是用来封装对象的创建

    ——工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体类编程。


    认识抽象工厂模式

    在之前的工厂模式已经创建了一个比萨工厂,但是真正要生产的产品——比萨,却还没有涉及到。

    比萨店会生产很多不同的比萨产品,而比萨又有格式不同风格的原料。

    所以,我们要建造一个工厂来生产原料,这个工厂将负责创建原料家族中的每一个原料:酱料、芝士、面团等。


    开始先为工厂定义一个接口,这个接口负责创建所有的原料:

    public interface PizzaIngredientFactory {
    
    	// 接口中,每个原料都有一个对应的方法创建该原料
    	// 下面方法返回各原料对象
    	public Dough createDough();
    	public Sauce createSauce();
    	public Cheese createCheese();
    	public Veggies[] createVeggies();
    	public Pepperoni createPepperoni();
    	public Clams createClam();
     
    }
    


    下面要做的是:

    1、给每个比萨店建造一个工厂。需要创建实现PizzaIngredientFactory接口的类,实现接口的方法。

    2、实现一组原料类供工厂使用。

    3、把这一切组织起来,将新的原料工厂整合进旧的PizzaStore中。


    下面创建了纽约原料工厂,实现了PizzaIngredientFactory接口:

    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();
    	}
    }
    


    然后就可以重新定义“比萨”,这个抽象类:

    public abstract class Pizza {
    	String name;
    
    	Dough dough;
    	Sauce sauce;
    	Veggies veggies[];
    	Cheese cheese;
    	Pepperoni pepperoni;
    	Clams clam;
    
    	abstract void prepare();//把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 box");
    	}
    
    	void setName(String name) {
    		this.name = name;
    	}
    
    	String getName() {
    		return name;
    	}
    
    	public String toString() {
    		StringBuffer result = new StringBuffer();
    		result.append("---- " + name + " ----
    ");
    		if (dough != null) {
    			result.append(dough);
    			result.append("
    ");
    		}
    		if (sauce != null) {
    			result.append(sauce);
    			result.append("
    ");
    		}
    		if (cheese != null) {
    			result.append(cheese);
    			result.append("
    ");
    		}
    		if (veggies != null) {
    			for (int i = 0; i < veggies.length; i++) {
    				result.append(veggies[i]);
    				if (i < veggies.length-1) {
    					result.append(", ");
    				}
    			}
    			result.append("
    ");
    		}
    		if (clam != null) {
    			result.append(clam);
    			result.append("
    ");
    		}
    		if (pepperoni != null) {
    			result.append(pepperoni);
    			result.append("
    ");
    		}
    		return result.toString();
    	}
    }
    



    然后就是创建真正的比萨了! 比萨店生产的比萨都是继承自Pizza类,假设要生产一个奶酪比萨(CheesePizza):

    // 这是应用了简单工厂模式
    // 比萨要用到原料,把生产原料任务委托给了ingredientFactory工厂
    public class CheesePizza extends Pizza {
    	PizzaIngredientFactory ingredientFactory;
     
    	public CheesePizza(PizzaIngredientFactory ingredientFactory) {
    		this.ingredientFactory = ingredientFactory;
    	}
            // 实现prepare方法
    	void prepare() {
    		System.out.println("Preparing " + name);
    		dough = ingredientFactory.createDough();
    		sauce = ingredientFactory.createSauce();
    		cheese = ingredientFactory.createCheese();
    	}
    }

    上面这个真正的比萨,是不是很眼熟?没错,起始就是简单工厂模式, Pizza利用相关的工厂生产原料。所生产的原料依赖所使用的工厂,Pizza类根本不关心这些原料,它只知道如何制作比萨。现在,Pizza和原料之间被解耦,无论原料工厂是在北京还是上海,Pizza类都可以轻易地复用。

    最后,是时候让新的比萨店登场了! 

    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;
    	}


    小结:

    上面一连串代码到底做了什么?

    其实就做了一件事,引入了新类型的工厂——抽象工厂,来创建比萨原料家族。

    我们创建了接口类PizzaIngredientFactory,这个接口可以创建产品的家族,利用这个接口,我们的代码将从实际工厂解耦,以便在不同上下文中实现各式各样的工厂,制作出不同的产品。


    定义抽象工厂模式

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


    抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么。这样一来,客户就从具体的产品中解藕。


    生产原料的类图:



    我们可以发现抽象工厂主要是为“产品”而服务的。



    抽象工厂的方法经常以工厂方法的方式实现(例如createDough(), createSource(),每个方法都被声明为抽象,而子类的方法覆盖这些方法来创建某些对象),抽象工厂的任务是定义一个负责创建一组产品的接口。这个接口内的每个方法都负责创建一个具体产品,同时我们利用实现抽象工厂的子类来提供这些具体的做法,所以,在抽象工厂中利用工厂方法实现生产的做法是相当自然的做法。



    比较工厂方法和抽象工厂


          抽象工厂和工厂方法都是负责创建对象,但工厂方法用的是继承,而抽象方法用的是对象的组合

          利用工厂方法创建对象,需要拓展一个类,并覆盖它的工厂方法。整个工厂方法模式,只不过就是通过子类来创建对象。用这种做法,客户只需要知道他们所使用的抽象类型就可以了,而由子类负责决定具体的类型,将客户从具体类型中解耦。

          而抽象工厂用来创建一个产品家族的抽象类型,这个类型的子类定义了产品被产生的方法。要想使用这个工厂,必须先实例化它,然后将它传入一些针对抽象类型所写的代码中。所以和工厂方法一样,也实现解耦。

          总之,他们都能将对象的创建封装起来,使应用程序解耦,并降低对特定实现的依赖。





  • 相关阅读:
    android问题及其解决-优化listView卡顿和怎样禁用ListView的fling
    平安科技移动开发二队技术周报(第三期)
    机房重构(个人版)——类图
    php-wamp环境搭建
    ajax 通过return 返回data值
    cocos2d-x中六种持续性动作
    Android SimpleAdapter
    jquery 判断当前上传文件大小限制上传格式 搭配thinkphp实现上传即预览(模拟异步上传)
    【转】我的第一个Python小程序
    python官网
  • 原文地址:https://www.cnblogs.com/pangblog/p/3246732.html
Copyright © 2011-2022 走看看