23种设计模式之工厂模式

披萨项目为例,使用工厂模式设计

需求:方便披萨品种扩展,便于维护,要能运行时扩展

披萨族(组)设计类图

假设只有原料不同,其他操作如烘焙、切割、打包相同,就把prepare方法设置为抽象方法

一般设计如下

//披萨族抽象类
public abstract class Pizza {

    protected String name;

    public abstract void prepare();

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

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

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

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

}
Pizza族抽象类
public class CheesePizza extends Pizza {
    public void prepare() {
        super.setName("CheesePizza");
        System.out.println(name + " preparing;");
    }
}
CheesePizza extends Pizza
public class GreekPizza extends Pizza {
    public void prepare() {
        super.setName("GreekPizza");
        System.out.println(name + " preparing;");
    }
}
GreekPizza extends Pizza
public class PepperPizza extends Pizza {
    public void prepare() {
        super.setName("PepperPizza");
        System.out.println(name + " preparing;");
    }
}
PepperPizza extends Pizza
public class OrderPizza {

    public OrderPizza() {
        Pizza pizza = null;
        String orderType;
        do {
            orderType = getType();
            if (orderType.equals("cheese")) {
                pizza = new CheesePizza();
            } else if (orderType.equals("greek")) {
                pizza = new GreekPizza();
            } else if (orderType.equals("pepper")) {
                pizza = new PepperPizza();
            } else {
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }

    private String getType() {
        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String pizzaType = bufferedReader.readLine();
            return pizzaType;
        } catch (Exception ex) {
            ex.printStackTrace();
            return "";
        }
    }

}
OrderPizza 用户通过输入pizza类型来点pizza
public class PizzaStore {

    public static void main(String[] args){
        OrderPizza orderPizza;
        orderPizza=new OrderPizza();
    }

}
pizza商店应用PizzaStore

这种设计有个问题就是,如果有新品种,那就要在披萨族中添加(即实现Pizza抽象类),再在OrderPizza类中添加else if判断,同样如果删除披萨品种也要修改这两个地方

简单工厂模式就可以把OrderPizza中创建Pizza部分(if else 变化 部分)抽出来

1、简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为

public class SimplePizzaFactory {

    public Pizza createPizza(String orderType){
        Pizza pizza=null;
        if (orderType.equals("cheese")) {
            pizza = new CheesePizza();
        } else if (orderType.equals("greek")) {
            pizza = new GreekPizza();
        } else if (orderType.equals("pepper")) {
            pizza = new PepperPizza();
        }
        return pizza;
    }

}
在OrderPizza中抽取出来的方法封装成简单工厂SimplePizzaFactory
public class OrderPizza {

    SimplePizzaFactory simplePizzaFactory;

    public OrderPizza(SimplePizzaFactory simplePizzaFactory) {
        setFactory(simplePizzaFactory);
    }

    public void setFactory(SimplePizzaFactory simplePizzaFactory) {
        this.simplePizzaFactory = simplePizzaFactory;
        Pizza pizza = null;
        String orderType;
        do {
            orderType = getType();
            pizza = simplePizzaFactory.createPizza(orderType);
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }

    private String getType() {
        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String pizzaType = bufferedReader.readLine();
            return pizzaType;
        } catch (Exception ex) {
            ex.printStackTrace();
            return "";
        }
    }
}

OrderPizza 改造后,就要使用简单工厂创建披萨实例
OrderPizza 改造后,就要使用简单工厂创建披萨实例
public class PizzaStore {

    public static void main(String[] args){
        OrderPizza orderPizza;
        orderPizza=new OrderPizza(new SimplePizzaFactory());
    }

}
PizzaStore 传入简单工厂实例对象

这样的简单工厂设计,增删披萨品种时只需在披萨族中增删披萨种类,和修改披萨工厂中方法,不需要改OrderPizza类

 2、工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类

假如要在伦敦和纽约开披萨分店,地域特色不同,披萨工厂也就不同了,也就是工厂是可变的了,那么为了不让OrderPizza类依赖于工厂,就把制作pizza方法变为抽象方法,OrderPizza类也就是抽象类了,也就是把工厂的实现放到子类去实现,伦敦工厂实现伦敦工厂方法,纽约工厂实现纽约工厂方法

开始有个Pizza族,现在又有个Pizza工厂族,即OrderPizza

工厂方法模式设计方案:将披萨项目里的披萨对象实例化功能抽象成抽象方法,在不同加盟店具体实现功能

public abstract class OrderPizza {

    public OrderPizza() {
        Pizza pizza = null;
        String orderType;

        do {
            orderType = getType();
            pizza=createPizza(orderType);

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

    public abstract Pizza createPizza(String orderType);


    private String getType() {
        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String orderType = bufferedReader.readLine();
            return orderType;
        } catch (Exception ex) {
            ex.printStackTrace();
            return "";
        }
    }
}
abstract class OrderPizza里面有abstract Pizza createPizza(String orderType)
public class LDCheesePizza extends Pizza {
    public void prepare() {
        super.setName("LDCheesePizza");
        System.out.println(name+" preparing;");
    }
}
LDCheesePizza extends Pizza
public class LDPepperPizza extends Pizza {
    public void prepare() {
        super.setName("LDPepperPizza");
        System.out.println(name+"preparing;");
    }
}
LDPepperPizza extends Pizza
public class NYCheesePizza extends Pizza {
    public void prepare() {
        super.setName("NYCheesePizza");
        System.out.println(name+"preparing;");
    }
}
NYCheesePizza extends Pizza
public class NYPepperPizza extends Pizza {
    public void prepare() {
        super.setName("NYPepperPizza");
        System.out.println(name+"preparing;");
    }
}
NYPepperPizza extends Pizza
public class LDOrderPizza extends OrderPizza {
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;

        if (orderType.equals("cheese")) {
            pizza = new LDCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}
LDOrderPizza extends OrderPizza
public class NYOrderPizza extends OrderPizza {
    public Pizza createPizza(String orderType) {
        Pizza pizza=null;

        if(orderType.equals("cheese")){
            pizza=new NYCheesePizza();
        }else if(orderType.equals("pepper")){
            pizza=new NYPepperPizza();
        }
        return pizza;
    }
}
NYOrderPizza extends OrderPizza
public class PizzaStore {

    public static void main(String[] args){
        OrderPizza orderPizza;
//        orderPizza=new LDOrderPizza();
        orderPizza=new NYOrderPizza();
    }
}
PizzaStore

简单工厂和工厂方法模式,看上去没有大的区别,但是在大型项目中,工厂方法模式就比较好,灵活性比较好点

3、抽象工厂模式:定义了一个接口用于创建相关或有依赖关系的对象族,而无需明确指定具体类(简单工厂演化)

public interface AbsFactory {

    Pizza createPizza(String orderType);

}
interface AbsFactory工厂接口
public class LDFactory implements AbsFactory {
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;

        if (orderType.equals("cheese")) {
            pizza = new LDCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}
LDFactory implements AbsFactory
public class NYFactory implements AbsFactory {
    public Pizza createPizza(String orderType) {
        Pizza pizza=null;

        if(orderType.equals("cheese")){
            pizza=new NYCheesePizza();
        }else if(orderType.equals("pepper")){
            pizza=new NYPepperPizza();
        }
        return pizza;
    }
}
NYFactory implements AbsFactory
public class OrderPizza {

    private AbsFactory absFactory;

    public OrderPizza(AbsFactory absFactory) {
        setFactory(absFactory);
    }

    public void setFactory(AbsFactory factory) {
        Pizza pizza = null;
        String orderType;

        this.absFactory = factory;

        do {
            orderType=getType();
            pizza=absFactory.createPizza(orderType);

            if(pizza!=null){
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }
        } while (true);
    }

    public String getType() {
        try {
            BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String orderType=bufferedReader.readLine();
            return orderType;
        }catch (Exception ex){
            ex.printStackTrace();
            return "";
        }
    }
}
OrderPizza
public class PizzaStore {

    public static void main(String[] args){
        AbsFactory absFactory;
        OrderPizza orderPizza;
        absFactory=new LDFactory();
        orderPizza=new OrderPizza(absFactory);
    }

}
PizzaStore

 4、依赖抽象原则

变量不要持有具体类的引用

不要让类继承自具体类,要继承自抽象类或接口

不要覆盖基类中已实现的方法

posted @ 2017-12-28 14:18  jiapeng  阅读(293)  评论(0编辑  收藏  举报