Head First设计模式读书笔记四 简单工厂 工厂模式 抽象工厂模式

版权声明:本文为博主原创文章,转载请注明出处 https://blog.csdn.net/u011109881/article/details/81146405

本文示例代码材料源自Head First设计模式
以前整理自己整理的链接:
工厂模式
https://blog.csdn.net/u011109881/article/details/56541580
抽象工厂
https://blog.csdn.net/u011109881/article/details/56730497

实例

假设现在要生产各种各样的Pizza,Pizza有不同的原料,就可以做出不同的Pizza,Pizza需要经过材料准备 烘焙 切片 打包等诸多过程。

没有学习设计模式之前,我们的代码可能是这样的:
这里写图片描述

public class PizzaStore {
    Pizza orderPizza(String type) {
        Pizza pizza;
        switch (type) {
        case "cheese":
            pizza = new CheesePizza();
            break;
        case "greek":
            pizza = new GreekPizza();
            break;
        default:
            pizza = new CheesePizza();
            break;
        }
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}
public class Pizza {

    public void prepare(){
        System.out.println("prepare");
    };

    public void bake(){
        System.out.println("bake");
    };

    public void cut(){
        System.out.println("cut");
    };

    public void box(){
        System.out.println("box");
    };
}

但是请思考一下,这样的代码易于扩展么?
比如我们要新加几种Pizza,原先的Pizza由于销量不好全部下架。那么我们只好进入orderPizza内部,对其进行一次“大手术”,而这违反了设计原则的对修改关闭对扩展开放的原则。

使用简单工厂(不算设计模式 只能算技巧)

我们再分析一下orderPizza的代码,可以发现生产Pizza的部分可能会经常变动,而包装过程不怎么变动。那么我们可不可以将变化的部分抽出来呢?
这里写图片描述

简单工厂类图

把变化的部分抽离出来,就是利用了简单工厂的思想。它的结构如下:
这里写图片描述

public class SimplePizzaFactory {

    public Pizza createPizza(String type){
        Pizza pizza;
        switch (type) {
        case "cheese":
            pizza = new CheesePizza();
            break;
        case "greek":
            pizza = new GreekPizza();
            break;
        default:
            pizza = new CheesePizza();
            break;
        }
        return pizza;

    }
}
public class PizzaStore {
    SimplePizzaFactory factory;
    public PizzaStore(SimplePizzaFactory factory) {
        this.factory = factory;
    }

    Pizza orderPizza(String type) {
        Pizza pizza;
        pizza = factory.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

聪明的读者也许一下子就会发现问题:这丫的不是自欺欺人掩耳盗铃么。没错,你是把变化的部分抽离了,放到了SimplePizzaFactory里面,但是这不过是把问题从一个地方转移到另一个地方么?问题仍然存在啊?
其实这样做有利于复用SimplePizzaFactory的代码,比如其他使用者需要对Pizza进行不同的加工。比如在门店购买的Pizza和饿了么送货的Pizza的处理应该不会相同。这样既分离了变化和不变的部分,又达成代码复用的目的。
这里写图片描述
在上面这个例子中PizzaStore中组合了SimplePizzaFactory对象,SimplePizzaFactory对象则组合了Pizza对象,Pizza对象又是各类Pizza的基类。简单工厂就是利用组合方式来分离变化与不变的部分的。

引入地域风情

现在,Pizza连锁店生意兴隆,风靡全国各地。比如上海苏州的Pizza会偏甜,湖南重庆的Pizza可能会放辣椒。
对于这种新加的元素,可以使用工厂模式。

使用工厂模式

类图:
这里写图片描述
这里写图片描述
(由于ProcessOn不能实现单个方法斜体,因此将抽象方法前面加上< A >表示抽象方法)

工厂模式代码实例

创建者类(creator)

public abstract class PizzaStore {
    Pizza pizza;
    public PizzaStore() {
    }

    public Pizza orderPizza(String type) {
        pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
    public abstract Pizza createPizza(String type);
}
public class CQPizzaStore extends PizzaStore{
    public CQPizzaStore() {
    }

    @Override
    public Pizza createPizza(String type) {
        switch (type) {
        case "cheese":
            pizza = new CQCheesePizza();
            break;
        case "greek":
            pizza = new CQGreekPizza();
            break;
        default:
            pizza = new CQCheesePizza();
            break;
        }
        return pizza;
    }
}
public class SHPizzaStore extends PizzaStore{
    public SHPizzaStore() {
    }

    @Override
    public Pizza createPizza(String type) {
        switch (type) {
        case "cheese":
            pizza = new SHCheesePizza();
            break;
        case "greek":
            pizza = new SHGreekPizza();
            break;
        default:
            pizza = new SHCheesePizza();
            break;
        }
        return pizza;
    }
}

产品类

public abstract class Pizza {
    String name;
    String dough;
    String sauce;
    ArrayList<String> toppings = new ArrayList<String>();

    public void prepare(){
        System.out.println("prepare "+ name);
        System.out.println("prepare Tossing "+dough);
        System.out.println("prepare Adding"+ sauce);
        System.out.println("prepare Adding toppings:");
        for(int i=0;i<toppings.size();i++){
            System.out.println(" "+toppings.get(i));
        }
    };

    public void bake(){
        System.out.println("bake");
    };

    public void cut(){
        System.out.println("cut");
    };

    public void box(){
        System.out.println("box");
    };

    public String getName(){
        return name;
    }
}
public class CQCheesePizza  extends Pizza{
    public CQCheesePizza(){
        name = "CQ Style Sauce and Cheese Pizza";
        dough = "Extar Thick Crust Dugh";
        sauce ="Plum Tomato Sauce";
        toppings.add("老干妈");
    }
}
public class CQGreekPizza  extends Pizza{
    public CQGreekPizza(){
        name = "CQ Style Sauce and Greek Pizza";
        dough = "Extar Thick Crust Dugh";
        sauce ="Plum Tomato Sauce";
        toppings.add("老干妈");
    }
}
public class SHCheesePizza  extends Pizza{
    public SHCheesePizza(){
        name = "SH Style Sauce and CHeese Pizza";
        dough = "Thin Crust Dugh";
        sauce ="Marinar Sauce";
        toppings.add("甜酱");
    }

}
public class SHGreekPizza  extends Pizza{
    public SHGreekPizza(){
        name = "SH Style Sauce and Greek Pizza";
        dough = "Thin Crust Dugh";
        sauce ="Marinar Sauce";
        toppings.add("甜酱");
    }

}

测试类

public class Test {

    public static void main(String[] args) {
        PizzaStore store = new CQPizzaStore();
        CQCheesePizza cqCheese = (CQCheesePizza) store.orderPizza("cheese");
        System.out.println();
        CQGreekPizza cqGreek = (CQGreekPizza) store.orderPizza("greek");
        System.out.println();
        store = new SHPizzaStore();
        SHCheesePizza shCheese = (SHCheesePizza) store.orderPizza("cheese");
        System.out.println();
        SHGreekPizza shGreek = (SHGreekPizza) store.orderPizza("greek");
        System.out.println();
    }

}

测试结果:

prepare CQ Style Sauce and Cheese Pizza
prepare Tossing Extar Thick Crust Dugh
prepare AddingPlum Tomato Sauce
prepare Adding toppings:
 老干妈
bake
cut
box

prepare CQ Style Sauce and Greek Pizza
prepare Tossing Extar Thick Crust Dugh
prepare AddingPlum Tomato Sauce
prepare Adding toppings:
 老干妈
bake
cut
box

prepare SH Style Sauce and CHeese Pizza
prepare Tossing Thin Crust Dugh
prepare AddingMarinar Sauce
prepare Adding toppings:
 甜酱
bake
cut
box

prepare SH Style Sauce and Greek Pizza
prepare Tossing Thin Crust Dugh
prepare AddingMarinar Sauce
prepare Adding toppings:
 甜酱
bake
cut
box

使用抽象工厂模式

抽象工厂模式类图

这里写图片描述
这里写图片描述

代码示例

原料基类

public class Cheese {

}
public class Clams {

}
public class Dough {

}
public class Pepperoni {

}
public class Sauce {

}
public class Veggies {

}

原料实体类(部分略)

public class PepperyCheese extends Cheese {

}
public class PepperyClam extends Clams{

}

public class PepperyDough extends Dough {

}
public class PepperyPepperoni extends Pepperoni {

}
public class PepperySauce extends Sauce {

}
public class RedPepper extends Veggies {

}

原料工厂类

public interface PizzaIngedientFactory {

    public Dough createDough();
    public Clams createClams();
    public Cheese createCheese();
    public Pepperoni createPepperoni();
    public Sauce createSauce();
    public Veggies[] createVeggies();
}
public class NYPizzaIngedientFactory implements PizzaIngedientFactory {

    @Override
    public Dough createDough() {
        System.out.println("createDough");
        return new ThinCrustDough();
    }

    @Override
    public Clams createClams() {
        System.out.println("createClams");
        return new FreshClam();
    }

    @Override
    public Cheese createCheese() {
        System.out.println("createCheese");
        return new ReggianoCheese();
    }

    @Override
    public Pepperoni createPepperoni() {
        System.out.println("createPepperoni");
        return new SlicedPepperoni();
    }

    @Override
    public Sauce createSauce() {
        System.out.println("createSauce");
        return new MarinaraSauce();
    }

    @Override
    public Veggies [] createVeggies() {
        System.out.println("createVeggies");
        Veggies veggies [] = {new Garlic() , new Onion(),new Mushroom(),new RedPepper()};
        return veggies;
    }

}
public class CQPizzaIngedientFactory implements PizzaIngedientFactory {

    @Override
    public Dough createDough() {
        System.out.println("createDough PepperyDough");
        return new PepperyDough();
    }

    @Override
    public Clams createClams() {
        System.out.println("createClams PepperyClam");
        return new PepperyClam();
    }

    @Override
    public Cheese createCheese() {
        System.out.println("createCheese PepperyCheese");
        return new PepperyCheese();
    }

    @Override
    public Pepperoni createPepperoni() {
        System.out.println("createPepperoni PepperyPepperoni");
        return new PepperyPepperoni();
    }

    @Override
    public Sauce createSauce() {
        System.out.println("createSauce PepperySauce");
        return new PepperySauce();
    }

    @Override
    public Veggies [] createVeggies() {
        System.out.println("createVeggies");
        Veggies veggies [] = {new Garlic() , new Onion(),new Mushroom(),new RedPepper()};
        return veggies;
    }

}

Pizza类

public abstract class Pizza {
    String name;
    Dough dough;
    Sauce sauce;
    Cheese cheese;
    Clams clam;
    ArrayList<Veggies> veggies = new ArrayList<Veggies>();
    PizzaIngedientFactory ingedientFactory;
    public abstract void prepare();

    public void bake(){
        System.out.println("bake");
    };

    public void cut(){
        System.out.println("cut");
    };

    public void box(){
        System.out.println("box");
    };

    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }

    @Override
    public String toString() {
        return name;
    }
}
public class CheesePizza extends Pizza {

    public CheesePizza(PizzaIngedientFactory ingedientFactory){
        this.ingedientFactory = ingedientFactory;
    }

    @Override
    public void prepare() {
        System.out.println("Preparing "+name);
        dough = ingedientFactory.createDough();
        sauce = ingedientFactory.createSauce();
        cheese = ingedientFactory.createCheese();
    }
}
public class ClamPizza extends Pizza {

    public ClamPizza(PizzaIngedientFactory ingedientFactory){
        this.ingedientFactory = ingedientFactory;
    }

    @Override
    public void prepare() {
        System.out.println("Preparing "+name);
        dough = ingedientFactory.createDough();
        sauce = ingedientFactory.createSauce();
        cheese = ingedientFactory.createCheese();
        clam = ingedientFactory.createClams();
    }
}

店铺类

public abstract class PizzaStore {
    Pizza pizza;
    public PizzaStore() {
    }

    public Pizza orderPizza(String type) {
        pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
    public abstract Pizza createPizza(String type);
}
public class CQPizzaStore extends PizzaStore{

    @Override
    public Pizza createPizza(String type) {
        PizzaIngedientFactory cqPizzaIngedientFactory = new CQPizzaIngedientFactory();
        switch (type) {
        case "cheese":
            pizza = new CheesePizza(cqPizzaIngedientFactory);
            pizza.setName("CQ cheese Pizza");
            break;
        case "clam":
            pizza = new ClamPizza(cqPizzaIngedientFactory);
            pizza.setName("CQ clam Pizza");
            break;
        }
        return pizza;
    }
}
public class NYPizzaStore extends PizzaStore{

    @Override
    public Pizza createPizza(String type) {
        PizzaIngedientFactory nyPizzaIngedientFactory = new NYPizzaIngedientFactory();
        switch (type) {
        case "cheese":
            pizza = new CheesePizza(nyPizzaIngedientFactory);
            pizza.setName("NY cheese Pizza");
            break;
        case "clam":
            pizza = new ClamPizza(nyPizzaIngedientFactory);
            pizza.setName("NY clam Pizza");
            break;
        }
        return pizza;
    }
}

测试类

public class Test {

    public static void main(String[] args) {
        PizzaStore store = new NYPizzaStore();
        CheesePizza nyCheesePizza = (CheesePizza) store.orderPizza("cheese");
        System.out.println();
        ClamPizza nyClamPizza = (ClamPizza) store.orderPizza("clam");
        System.out.println();

        PizzaStore store2 = new CQPizzaStore();
        CheesePizza cqCheesePizza = (CheesePizza) store2.orderPizza("cheese");
        System.out.println();
        ClamPizza cqClamPizza = (ClamPizza) store2.orderPizza("clam");
        System.out.println();
    }

}

关于工厂模式和抽象工厂模式的区别和联系

从上述工厂模式和抽象工厂模式的UML类图来看,其实工厂模式是存在于抽象工厂模式里面的。注意看如下共通部分:
工厂模式截图
这里写图片描述
抽象工厂模式部分截图
这里写图片描述
两种模式都是通过PizzaStore来生产产品。只不过,抽象工厂模式更为复杂一些。因为,它包含了一系列的产品原料,它更适合于生产零件很多,不同搭配可以生产不同产品的情况。
另外,这两种模式都包含生产对象的方法(本例中是createPizza方法),子类只要继承并实现该方法,就可以生产对象了,因此他们都是用于生产对象的模式,只不过抽象工厂模式中间加入了一个工厂来生成对象,他们将需要产品的客户端(本例中为测试类)与实际产品(本例中是Pizza)解耦。
所以工厂模式和抽象工厂模式还是很像的,区别相对较小。

猜你喜欢

转载自blog.csdn.net/u011109881/article/details/81146405
今日推荐