1-4 工厂模式(工厂方法模式/抽象工厂模式)

工厂模式

注意:接口:泛指狭义上的接口,也可以指抽象类

概念解释

  1. 工厂方法模式:
    定义一个创建对象的接口,但由子类决定实例化的具体类型。即,将类的实例化推迟到了子类。
  2. 抽象工厂模式
    提供一个接口,用于创建相关或依赖对象的家族。也是吧类的实例推迟到了子类
    具体区别下文会有介绍。
    1. 简单工厂的方式 不是设计模式,更多的是一种编码规范。

需求1

创建一个不同地区(纽约、芝加哥)风味的披萨点 生产的不同种类( chessse veggie)披萨

1 普通实现

// 披萨店直接做具体类型的披萨 耦合性极大
public class DependentPizzaStore {
    public Pizza createPizza(String style, String type) {
        Pizza pizza = null;
        if (style.equals("NY")) {
            if (type.equals("cheese")) {
                pizza = new NYStyleCheesePizza();
            } else if (type.equals("veggie")) {
                pizza = new NYStyleVeggiePizza();
            } 
        } else if (style.equals("Chicago")) {
            if (type.equals("cheese")) {
                pizza = new ChicagoStyleCheesePizza();
            } else if (type.equals("veggie")) {
                pizza = new ChicagoStyleVeggiePizza();
            }
        } else {
            System.out.println("Error: invalid type of pizza");
            return null;
        }
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

2 简单工厂产生具体披萨 披萨店调用工厂做出具体披萨

简单工厂其实不是一个设计模式,更像是一种变成习惯

// 普通做法相比 只是将做披萨封装出去,有工厂提供。
public class SimplePizzaFactory {
    public Pizza createPizza(String type) {// type 类型 即代表披萨店区域,又代表披萨的种类。两个维度 这样不好
        Pizza pizza = null;
        if (type.equals("NYcheese")) {
            pizza = new NYCheesePizza();
        } else if (type.equals("NYveggie")) {
            pizza = new NYVeggiePizza();
        }else if (type.equals("Chicagocheese")) {
            pizza = new ChicagoCheesePizza();
        } else if (type.equals("Chicagoveggie")) {
            pizza = new ChicagoVeggiePizza();
        }
        return pizza;
    }
}
public class PizzaStore {
    SimplePizzaFactory factory;
    public PizzaStore(SimplePizzaFactory factory) { 
        this.factory = factory;
    }
    public Pizza orderPizza(String type) {
        Pizza pizza = factory.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }
}

3 工厂方法模式

// 把做什么风味的决定权交给披萨店(PizzaStore)  把做披萨还得限制于具体PizzaStore类中
public abstract class PizzaStore {
    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;
    }
    // 由子披萨店,即各地区披萨店自主决定(pizzaStore的类型)披萨风味和披萨种类(type)
    abstract Pizza createPizza(String type);
}
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 return null;
    }
}
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 return null;
    }
}
// 测试
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("veggie");
        System.out.println("Ethan ordered a " + pizza.getName() + "\n");

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

// 公共代码
public abstract class Pizza {
    //原料 下边会有对原料的变体
    String name;
    String dough;
    String sauce;
    String veggie;
    String clam;
    String perpersoni;
    ArrayList<String> toppings = new ArrayList<String>();

    void prepare() {// 对基本披萨的处理
        System.out.println("Prepare " + name);
        System.out.println("Tossing dough...");
        System.out.println("Adding sauce...");
        System.out.println("Adding toppings: ");
        for (String topping : toppings) {
            System.out.println("   " + topping);
        }
    }
    void bake() {
        System.out.println("Bake for 25 minutes at 350");
    }
    void cut() {
        System.out.println("Cut the pizza into diagonal slices");
    }
    void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }
    public String getName() {
        return name;
    }
    public String toString() {
        StringBuffer display = new StringBuffer();
        display.append("---- " + name + " ----\n");
        display.append(dough + "\n");
        display.append(sauce + "\n");
        for (String topping : toppings) {
            display.append(topping + "\n");
        }
        return display.toString();
    }
}
public class ChicagoStyleCheesePizza extends Pizza {
    public ChicagoStyleCheesePizza() { 
        name = "Chicago Style Deep Dish Cheese Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";

        toppings.add("Shredded Mozzarella Cheese");
    }

    void cut() {
        System.out.println("Cutting the pizza into square slices");
    }
}
public class NYStyleCheesePizza extends Pizza {
    public NYStyleCheesePizza() { 
        name = "NY Style Sauce and Cheese Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";

        toppings.add("Grated Reggiano Cheese");
    }
}
简单工厂与工厂方法的区别

简单工厂把全部工作在一个地方都处理完了;它把创建产品的代码封装起来,但不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品
抽象工厂方法却是创建一个框架,让子类决定如何实现,即子类决定产品类型

需求2 保证风味种类或者说原料都得是指定的

用对象来限定种类

4 抽象工厂模式

//定义产生产品家族的接口-抽象工厂
public interface PizzaIngredientFactory {
    //每种原料就是一种类
    public Dough createDough();
    public Sause createSause();
    public Cheese createCheese ();
}
// 具体工厂决定具体的产品
public NYPizzaIngredientFactory implements PizzaIngredientFactory {
    public Dough createDough(){
        return ThinCrustDoough();
    }
    public Sause createSause(){
        return MarinaraSause();
    }
}
// 给披萨加上配料
public abstract class Pizza{
    public Dough dough;
    public Sause sause;
    public Veggies veggies[];
    public Cheese cheese;
    public Peppersoni perppersoni;
    public Clams clams;


    abstract void prepare();// 声明称抽象,从原料工厂中获取pizza所需的具体风味原料
    void bake() {
        System.out.println("Bake for 25 minutes at 350");
    }
    void cut() {
        System.out.println("Cut the pizza into diagonal slices");
    }
    void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }
    public String getName() {
        return name;
    }
    public String toString() {
        StringBuffer display = new StringBuffer();
        display.append("---- " + name + " ----\n");
        display.append(dough + "\n");
        display.append(sauce + "\n");
        for (String topping : toppings) {
            display.append(topping + "\n");
        }
        return display.toString();
    }
}
//具体类型的披萨
public ChessPizza extends Pizza{
    PizzaIngredientFactory pizzaIngredientFactory; // 盛放具体类型的原料工厂
    public ChessPizza(PizzaIngredientFactory pizzaIngredientFactory){
        this.pizzaIngredientFactory = pizzaIngredientFactory;
    }

    @Override
    public void prepare(){
        this.dough = pizzaIngredientFactory.getDough();
        this.sause= pizzaIngredientFactory.getSause();
    }
}
public Veggiesizza extends Pizza{
    PizzaIngredientFactory pizzaIngredientFactory; // 盛放具体类型的原料工厂
    public ChessPizza(PizzaIngredientFactory pizzaIngredientFactory){
        this.pizzaIngredientFactory = pizzaIngredientFactory;
    }

    @Override
    public void prepare(){// 具体风味的不同,及配料的不同
        this.dough = pizzaIngredientFactory.getDough();
        this.sause= pizzaIngredientFactory.getSause();
        this.veggies= pizzaIngredientFactory.getVeggies();
    }
}
//纽约地区的披萨店
public NYPizzaStore extends PizzaStore {
    Pizza pizza = null;
    PizzaIngredientFactory pizzaIngredientFactory = new NYPizzaIngredientFactory();//NYPizzaIngredientFactory是NYPizzaStore披萨店的配料
    @Override
    public Pizza createPizza(String type){
        if("cheese".equals(type)){ 
            pizza = new CheesePizza(pizzaIngredientFactory);
        }
        if("veggie".equals(type)){
            pizza = new Veggiesizza(pizzaIngredientFactory);
        }
    }
} 
//测试
public orderPizzaTest{
    main(String[] args){
        //由子类决定store 以及风味(配料)的类型
        PizzaStore nyStore = new NYPizzaStore();
        PizzaIngredientFactory nyPizzaIngredientFactory  = new NYPizzaIngredientFactory();

        Pizza chessPizza = nyStore.orderPizza("cheese"); //完成了下边的工作 
             - //一旦确定了PizzaStore的类型,也就确定了原料工厂类型;设置"cheese"类型时,把原料工厂类型设置给了chessPizza;
             - // Pizza chessPizza = createPissa("cheese"); 完成了基本的创建
             - // chessPizza = chessPizza.prepare()//pizza的具体类型调用后续处理,将原料设置给了基本的披萨
    }
}


工厂方法和抽象工厂的区别

  1. 类/对象

    工厂方法使用的是类, 去继承一个类,并覆盖它的工厂方法;
    抽象工厂使用的是对象, 去组合。

  2. 实例化一个产品/一群产品
    这也说明了两者的使用场景;
    抽象方法模式中的方法其实就是工厂模式实现的



脑袋有点蒙了 ,有时间再做更正

发布了13 篇原创文章 · 获赞 10 · 访问量 1644

猜你喜欢

转载自blog.csdn.net/navigator2015/article/details/72955035