欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

设计模式1-工厂模式

程序员文章站 2022-03-09 21:36:27
...

场景:假设开了一家披萨店,可以生产不同种类的披萨,客人点单的时候是根据点单类型(type)确定生产哪种披萨。

一.原始操作

1.比萨接口

public interface Pizza {

    public void prepare();

    public void bake();

    public void cut();

    public void box();

}

2.具体披萨种类的操作

/**2.芝士比萨*/
public class CheesePizza implements Pizza {

    @Override
    public void prepare() {
        System.out.println("开始准备芝士比萨");
    }

    @Override
    public void bake() {
        System.out.println("开始烘焙芝士比萨");
    }

    @Override
    public void cut() {
        System.out.println("开始将芝士比萨分块");
    }

    @Override
    public void box() {
        System.out.println("开始打包芝士比萨");
    }

}

/**3.蛤蜊比萨*/
public class ClamPizza implements Pizza {

    @Override
    public void prepare() {
        System.out.println("开始准备蛤蜊比萨");
    }

    @Override
    public void bake() {
        System.out.println("开始烘焙蛤蜊比萨");
    }

    @Override
    public void cut() {
        System.out.println("开始将蛤蜊比萨分块");
    }

    @Override
    public void box() {
        System.out.println("开始打包蛤蜊比萨");
    }

}

3.披萨店点单(菜单)

public class PizzaStore {

    public void orderPizza(String type) {
        Pizza pizza = null;

        if("cheese".equals(type)) {
            pizza = new CheesePizza();
        } else if ("clam".equals(type)) {
            pizza = new ClamPizza();
        } else if("veggie".equals(type)) {
            pizza = new VeggiePizza();
        }

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
    }

}

问题:如果有了新品种,点单的菜单要修改(这个对客户造成了影响orderPizza),具体披萨种类的也要添加和修改

二.简单工厂编程习惯

改进1:我们可以定义一个工厂,由工厂来根据客人点单类型生产不同的披萨,披萨店只需要提供菜单即可(外包)。

1.找到一家工厂(外包公司)可以生产菜单上的披萨

public class SimplePizzaFactory {

    public Pizza createPizza(String type) {
        Pizza pizza = null;

        if("cheese".equals(type)) {
            pizza = new CheesePizza();
        } else if("clam".equals(type)) {
            pizza = new ClamPizza();
        } else if("veggie".equals(type)) {
            pizza = new VeggiePizza();
        }

        return pizza;
    }
}

2.披萨店提供菜单(需要依赖外包公司)

public class PizzaStore {

    SimplePizzaFactory factory;

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

    public void orderPizza(String type) {
        Pizza pizza = factory.createPizza(type);

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
    }

}

优点:将生产具体披萨的过程封装到了工厂类,如果有新披萨种类,只需要修改工厂类即可,对菜单不会造成什么影响,这样对顾客是没有影响的。

需求:要有新店加盟了,工厂只有一种生产披萨的方法,但是不同的分店有着不同的生产方法,找工厂不行了,自己加工吧。

三.工厂模式1-工厂方法模式

1.抽象商标

public abstract class PizzaStore {

    public abstract Pizza createPizza(String type);

    public void orderPizza(String type) {
        Pizza pizza = createPizza(type);

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
    }

}

2.各地加盟的分店(用一个商标)(继承)

/**1.纽约分店*/
public class NYPizzaStore extends PizzaStore {

    @Override
    public Pizza createPizza(String type) {
        Pizza pizza = null;

        if("cheese".equals(type)) {
            pizza = new NYCheesePizza();
        } else if("clam".equals(type)) {
            pizza = new NYClamPizza();
        } else if("veggie".equals(type)) {
            pizza = new NYVeggiePizza();
        }

        return pizza;
    }

}
/**芝加哥分店*/
public class ChicagoPizzaStore extends PizzaStore {

    @Override
    public Pizza createPizza(String type) {
        Pizza pizza = null;

        if("cheese".equals(type)) {
            pizza = new ChicagoCheesePizza();
        } else if("clam".equals(type)) {
            pizza = new ChicagoClamPizza();
        } else if("veggie".equals(type)) {
            pizza = new ChicagoVeggiePizza();
        }
        return pizza;
    }
}

需求:每个分店根据自己的加工步骤,自己的原材料加工自己店的披萨,但是原材料总是不够用,需要一个原料工厂(每个分店需要的原材料的种类的组合不一样)

四.工厂模式2-抽象工厂模式

1.抽象的材料工厂(可以生产各种原料,具体的原料类型根据不同的店的需求来组合)

public interface PizzaIngredientFactory {

    public Cheese createCheese();

    public Dough createDough();

    public Veggie createVeggie();

    public Clam createClam();

}

2.各个分店需要的具体材料组合


## /**1.纽约材料工厂*/

public class NyPizzaIngredientFactory implements PizzaIngredientFactory {

    @Override
    public Cheese createCheese() {
        return new ReggianoCheese();
    }

    @Override
    public Dough createDough() {
        return new ThinCrustDough();
    }

    @Override
    public Veggie createVeggie() {
        return new NyStyleVeggie();
    }

    @Override
    public Clam createClam() {
        return new FreshClam();
    }

}

## /**2.芝加哥材料工厂*/

public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory {

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

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

    @Override
    public Veggie createVeggie() {
        return new ChicagoStyleVeggie();
    }

    @Override
    public Clam createClam() {
        return new FrozenClam();
    }

}

3.重新定义披萨(设置材料属性)

public abstract class Pizza {
    Cheese cheese;
    Dough dough;
    Veggie veggie;
    Clam clam;

    public abstract void prepare();

    public void bake() {
        System.out.println("开始烘焙");
    }

    public void cut() {
        System.out.println("开始将比萨切块");
    }

    public void box() {
        System.out.println("开始打包比萨");
    }

}

4.就某一家披萨店来点单(披萨原料依赖具体的工厂)

public class NYPizzaStore extends PizzaStore {

    @Override
    public Pizza createPizza(String type) {
        Pizza pizza = null;
        PizzaIngredientFactory factory=new NyPizzaIngredientFactory();

        if("cheese".equals(type)) {
            pizza = new NYCheesePizza(factory);
        } else if("clam".equals(type)) {
            pizza = new NYClamPizza(factory);
        } else if("veggie".equals(type)) {
            pizza = new NYVeggiePizza(factory);
        }

        return pizza;
    }
}

五.定义和总结

抽象工厂模式 提供了一个接口,用于创建相关或依赖对象的家族(披萨依赖原料工厂),而不需要明确指定具体类。(对象的组合)
工厂方法模式 定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。(具体对象的创建)

所有的工厂都是用来封装对象的创建,所有的工厂模式都是通过减少应用程序和具体类之间的依赖促进松耦合。

工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象。
抽象工厂使用对象组合:对象的创建被实现在工厂接口暴露出来的方法中。

依赖倒置原则:避免依赖具体的类型,尽量依赖抽象。