设计模式-工厂相关模式

52 阅读2分钟

设计模式- 工厂相关模式

简单工厂

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

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

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

    public String getName(){
        return name;
    }
}

public class SimplePizzaFactory {
    public Pizza createPizza(String type){
        Pizza pizza = null;
        if (type.equals("cheese")){
            pizza = new CheesePizza();
        }else if(type.equals("peoperoni")){
            pizza = new PepperoniPizza();
        }
        return pizza;
    }
}

// 这是生产pizza的工厂类
//
//
/* 当有很多客户端调用这个工厂时,那抽出这个为公共的工厂,修改就只需要修改这个公共的工厂 */

工厂方法

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

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

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

    public String getName(){
        return name;
    }
}

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

     }

     abstract Pizza CreatePizza(String type);
}

//这是工厂方法,感觉也不是很灵活,把创建pizza的factor工厂类改成CreatePizza方法。生产pizza的方法由每个store的createpizza来制定
/*
简单工厂和工厂方法的比较:

简单工厂把全部的事情,在一个地方都处理完了,然后工厂方法却是创建一个框架,让子类决定要如何实现。比如说,在工厂方法中,CreatePizza
 */
 
 
 public class ChicagoPizzaStore extends PizzaStore {
    @Override
    Pizza CreatePizza(String type) {
        if(type.equals("cheese")) {
            return new ChicagoStyleCheesePizza();
        }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 放在一个if,else结构里封装成函数,传参进行选择。优点简点,缺点不符合开闭原则,耦合度高
简单工厂: 就是把创建产品列表封装成一个对象,相对来说修改只需要修改对象本身,而且对象共享使用,符合开闭原则,但是不具备扩展性。
相对来说修改只需要修改对象本身,而且对象共享使用,符合开闭原则,但是不具备扩展性。
比如你有a,b,c三款pizza,全国有几百家分店,不同地区分店pizza类别虽一样,但是调料和做法有所差异,这样你就得为不同地区建立不同的工厂以提供不同口味
的pizza,这时如果只有一个工厂就不符合了。于是有了第二种 工厂方法。
工厂方法:  就是把创建产品做成一个抽象方法,每家店可以自定义这个抽象方法。通过在基类定义createPizza为抽象方法,来实现多态,但是于此同时,你需要
创建不同pizza类,于是就有了抽象方法耦合多个pizza类。这就违反了一个原则依赖倒置原则:更高层的组件依赖具体的类,而不是依赖抽象。

在工厂方法的代码案例里,pizza的生产材料是直接创建类实例时创建的。

如何解决?
多一层抽象,还记得第一章的设置原则吗,动静分离,把不变的分成一个组件(类),把变的分成另一个(接口),然后两者组合。

原先工厂方法的是做法是:pizza是基类,继承了 area_type_pizza,所以是n * n个 pizza.

每个pizzaStore的createPizza抽象方法耦合了n个pizza实体类


现状问题:创建多个n * n pizza类,createPizza耦合多个实体类而不是抽象。

抽象工厂模式:
主要做了以下的优化
1.把pizza的生产改成根据area(提供原料)抽像成interface,解决原先抽象方法createPizza的面向具体类编程,转而改成面向PizzaIngredientFactory抽象编程。
2. pizza类的生成材料不在是每个类里单独垂直创建,而是委托工厂创建(每个店都有独立一个工厂,提供了pizza的材料)
3. 原来要创建的n(area)* n(type) 个pizza,现在变成只需要创建n个type pizza,但同时pizza的材料不再是由类写死,而是去指定区域的factory里取。但是factory指定了各种各样的材料,这个是有耦合的。

pizzaStore(is) NYPizzStore -> (has) pizza (is kind of Pizza)--> has(材料Factor) ---> has各种材料(dough、clams、pepperoni、veggies、sauce、chess不符合开闭原则) --> (is) kind of(材料)

PizzaStore(店)  CreatePizza函数,需要有Pizza和factor对象。 有各种类型的pizza
Pizza -- prepare函数 (has) -- (Factor) has -- (材料)。 
dough、sauce、veggies、cheese、pepperoni、clam 等材料是多态的。
工厂是不太符合开闭原则,因为要硬编码写入各种材料




抽象工厂代码

image-20220726193105977.png

# ============ pizza的材料接口 ==================
public interface Cheese {
    public String getCheese();
    public String toString();
}

public interface Clams {
    public String getClams();
    public String toString();
}

public interface Dough {
    public String getDough();
    public String toString();
}

public interface Pepperoni {
    public String toString();
}

public interface Sauce {
    public String getSauce();
    public String toString();
}

public interface Veggies {
    public String toString();
}

# ============== pizza 类==============

public abstract class Pizza {
    String name;
    Dough dough;
    Sauce sauce;
    Veggies veggies[];
    Cheese cheese;
    Pepperoni pepperoni;
    Clams clam;

    abstract void prepare();
    /* 需要去工厂类里取pizza的材料 */

    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;
    }
    public String getName(){
        return name;
    }

    public String toString(){

    }
}


public class CheesePizza extends Pizza {
    PizzaIngredientFactory ingredientFactory;

    public CheesePizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory = ingredientFactory;
    }

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


public class VeggiePizza extends Pizza{
    PizzaIngredientFactory ingredientFactory;

    public VeggiePizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory = ingredientFactory;
    }

    void prepare(){
        System.out.println("Preparing " + name);
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
        Veggies[] veggies = ingredientFactory.createVeggies();
    }
}
/* 工厂接口提供各种材料,各种pizza可以定制选择材料组合  */


# ============== Factory 接口和类 ==================

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



public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
    @Override
    public Dough createDough() {
        return new ThinCrustDough();
    }
    /* 纽约工厂pizza面的材料 */
    public Sauce createSauce(){
        return new MarinaraSauce();
    }

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

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

    @Override
    public Pepperoni createPPeroni() {
        return new SlicePepperoni();
    }

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

===============================Pizzstore =======================
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 VeggePizza(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;
    }
}