1. 程式人生 > >23種設計模式之工廠模式

23種設計模式之工廠模式

stream -a cdd 一個 sim ted bfd 變化 行為

披薩項目為例,使用工廠模式設計

需求:方便披薩品種擴展,便於維護,要能運行時擴展

披薩族(組)設計類圖

技術分享圖片

假設只有原料不同,其他操作如烘焙、切割、打包相同,就把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、依賴抽象原則

變量不要持有具體類的引用

不要讓類繼承自具體類,要繼承自抽象類或接口

不要覆蓋基類中已實現的方法

23種設計模式之工廠模式