1. 程式人生 > 實用技巧 >java設計模式2-工廠模式

java設計模式2-工廠模式

工廠模式

工廠模式屬於建立型模式.提供了一種建立物件的最佳方式.

介紹

定義一個建立物件的介面,讓其子類自己決定例項化哪一工廠類,工廠模式使其建立過程延遲到子類進行.

應用例項一

您需要一輛汽車,可以直接從工廠裡面提貨,而不用去管這倆汽車是怎麼做出來的,如果想新增一個產品,只有擴充套件一個工廠類就可以,遮蔽了產品的具體實現,呼叫者只關心產品的介面.

看一個具體需求

如一個披薩專案:要便於披薩種類的擴充套件、要便於維護

1、披薩的種類很多()

2、披薩的製作有preparebakecutbox

3、完成披薩店訂購功能

使用傳統方法

編寫OrderPizza.java去訂購需要的各種Pizza

public class OrderPizza {

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

        do {
            orderType = getType();
            if (orderType.equals("greek")) {
                pizza = new GreekPizza();
                pizza.setName("GreekPizza....");
            } 
else if (orderType.equals("cheese")) { pizza = new CheesePizza(); pizza.setName("cheese...."); } else if (orderType.equals("pepper")) { pizza = new PepperPizza(); pizza.setName("PepperPizza...."); } else {
break; } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } private String getType() { Scanner scanner = new Scanner(System.in); System.out.println("請輸入相應訂購的型別"); String orderType = scanner.nextLine(); return orderType; } }

傳統方式的優缺點

1、優點是比較好理解,簡單易操作

2、缺點是違反了設計模式的ocp原則,即對擴充套件開發,對修改關閉.當我們給類增加新功能時,儘量不修改程式碼,

比如我們要增加新Pizza,需要作如下修改

orderType = getType();
if (orderType.equals("greek")) {
    pizza = new GreekPizza();
    pizza.setName("GreekPizza....");
} else if (orderType.equals("cheese")) {
    pizza = new CheesePizza();
    pizza.setName("cheese....");
} else if (orderType.equals("pepper")) {
    pizza = new PepperPizza();
    pizza.setName("PepperPizza....");
} else {
    break;
}

改進思路分析

分析:修改程式碼可以接受,但是如果我們在其他地方也有建立Pizza的程式碼,就意味著,也需要修改,而建立的程式碼,往往有多處.

思路:把建立Pizza物件封裝到一個類中,這樣我們有新的Pizza種類時,只需要修改該類就可,其他有建立物件的程式碼就不需要修改了--》簡單工廠模式

基本介紹

1、簡單工廠模式是屬於建立型模式,是工廠模式的一種.簡單工廠模式是由一個工廠物件決定創建出哪一種產品類的例項.簡單工廠是工廠模式家族中最簡單實用的模式

2、簡單工廠模式:定義了一個建立物件的類,由這個類來封裝例項物件的行為

在軟體開發中,我們會用到大量的建立某種、某類或者某批物件時,就會使用到工廠模式.

使用簡單工廠模式

簡單工廠模式的設計方法:定義一個可以例項化Pizza物件的類,封裝建立物件的程式碼.

public class SimpleFactory {

    // orderType 返回對應的 Pizza 物件
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        System.out.println("使用簡單工廠模式");
        if (orderType.equals("greek")){
            pizza = new GreekPizza();
            pizza.setName("GreekPizza////");
        }else if (orderType.equals("cheese")){
            pizza = new CheesePizza();
            pizza.setName("CheesePizza////");
        }else if (orderType.equals("pepper")){
            pizza = new PepperPizza();
            pizza.setName("PepperPizza////");

        }
        return pizza;
    }

orderPizza

public class OrderPizza {

    SimpleFactory simpleFactory;
    Pizza pizza = null;

    public OrderPizza(SimpleFactory simpleFactory) {
        setFactory(simpleFactory);
    }

    private void setFactory(SimpleFactory simpleFactory) {
        this.simpleFactory = simpleFactory;
        String orderType;

        do {
            orderType = getType();
            pizza = this.simpleFactory.createPizza(orderType);


            if (pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println(" 訂購披薩失敗 ");
                break;
            }
        } while (true);

    }

    private String getType() {
        try {
            BufferedReader string = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 種類:");
            String str = string.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

}

工廠方法模式

看一個新的需求

客戶在點披薩時,可以點不同口味的披薩,比如,北京的乳酪pizza、北京的胡椒pizza或者是倫敦的乳酪pizza、倫敦的胡椒pizza

思路1

使用簡單工廠模式,建立不同的簡單工廠類,比如BJPizzaSimpleFactoryLDPizzaSimpeFactory等等.從當前這個案例,也是可以的.但是考慮到專案的規模,以及軟體的可維護性、可擴充套件性並不是特別好.

思路2

使用工廠方法模式

基本介紹

1、工廠方法模式設計方法:將披薩專案的例項化功能抽象成抽象方法,在不同的口味點餐子類中具體實現.

2、工廠方法模式:定義了一個建立物件的抽象方法,由子類決定要例項化的類.工廠方法模式將物件的例項化推遲到子類

工廠方法模式應用案例

1、披薩專案新的需求:客戶在點披薩時,可以點不同口味的披薩,比如北京的乳酪pizza、北京的胡椒pizza,還可以選不同地區的pizza,倫敦乳酪pizza、倫敦的胡椒pizza

思路分析圖解

OrderPizza

public abstract class OrderPizza {

    abstract Pizza createPizza(String orderType);

    OrderPizza() {
        Pizza pizza = null;
        String orderType = null;
        do {
            orderType = getType();
            pizza = createPizza(orderType);

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

    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 種類:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

}

BJOrderPizza

public class BJOrderPizza extends OrderPizza {
    @Override
    Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}

LDOrderPizza

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

抽象工廠模式

基本介紹

1、抽象工廠模式:定義了一個interface用於建立相關或有依賴關係的物件簇,而無需指明具體的類.

2、抽象工廠模式可以將簡單工廠模式和工廠方法模式進行整合

3、從設計層面看,抽象工廠模式就是對簡單工廠模式的改進(或者稱為進一步的抽象)

將工廠抽象成兩層,AbsFactory和具體實現的工廠子類.程式設計師可以根據建立物件型別使用對應的工廠子類.這樣將單個的簡單工廠類變成了工廠簇,更利於程式碼的維護和擴充套件

抽象工廠模式應用例項

public interface AbsFactory {
    public Pizza createPizza(String orderType);
}

public class BJFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        System.out.println("~使用的是抽象工廠模式~");
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}

public class LDFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        System.out.println("~使用的是抽象工廠模式~");
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new LDCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}

public class OrderPizza {
    AbsFactory factory;

    // 構造器
    public OrderPizza(AbsFactory factory) {
        setFactory(factory);
    }

    private void setFactory(AbsFactory factory) {
        Pizza pizza = null;
        // 使用者輸入
        String orderType = "";
        this.factory = factory;
        do {
            orderType = getType();
            // factory 可能是北京的工廠子類,也可能是倫敦的工廠子類
            pizza = factory.createPizza(orderType);
            // 訂購 ok
            pizza.prepare();
            if (pizza != null) {
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println("訂購失敗");
                break;
            }
        } while (true);
    }

    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 種類:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }

    }
}

工廠模式在JDK-Calendar應用的原始碼分析

1、JDK中的Calendar類中,就使用了簡單工廠模式

private static Calendar createCalendar(TimeZone zone,
                                       Locale aLocale)
{
    CalendarProvider provider =
        LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                             .getCalendarProvider();
    if (provider != null) {
        try {
            return provider.getInstance(zone, aLocale);
        } catch (IllegalArgumentException iae) {
            // fall back to the default instantiation
        }
    }

    Calendar cal = null;

    if (aLocale.hasExtensions()) {
        String caltype = aLocale.getUnicodeLocaleType("ca");
        if (caltype != null) {
            switch (caltype) {
            case "buddhist":
            cal = new BuddhistCalendar(zone, aLocale);
                break;
            case "japanese":
                cal = new JapaneseImperialCalendar(zone, aLocale);
                break;
            case "gregory":
                cal = new GregorianCalendar(zone, aLocale);
                break;
            }
        }
    }
    if (cal == null) {
        // If no known calendar type is explicitly specified,
        // perform the traditional way to create a Calendar:
        // create a BuddhistCalendar for th_TH locale,
        // a JapaneseImperialCalendar for ja_JP_JP locale, or
        // a GregorianCalendar for any other locales.
        // NOTE: The language, country and variant strings are interned.
        if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
            cal = new BuddhistCalendar(zone, aLocale);
        } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                   && aLocale.getCountry() == "JP") {
            cal = new JapaneseImperialCalendar(zone, aLocale);
        } else {
            cal = new GregorianCalendar(zone, aLocale);
        }
    }
    return cal;
}

工廠模式小結

1、工廠模式的意義

  a)將例項化物件的程式碼提取出來,放到一個類中統一管理和維護,達到和主專案的依賴關係的解耦.從而提高專案的擴充套件和維護性.

2、三種工廠模式(簡單工廠模式、工廠方法模式、抽象工廠模式)

  a)簡單工廠模式:

簡單工廠模式是由一個工廠物件決定創建出哪一種產品類的例項,將建立物件的程式碼提取到一個工廠中(simpleFactory),保證單一原則.

  b)工廠方法模式:將訂購物件的程式碼抽象為方法,提高可維護性、可擴充套件性

  c)抽象工廠模式:將建立物件的方法抽象,並將工廠抽象,進一步提高可維護性、可擴充套件性

  d) 工廠方法跟抽象工廠區別是抽象工廠抽象了兩層(介面+具體實現子類,而工廠方法是抽象類出現方法)

3、設計模式的依賴抽象原則

  1、建立物件例項時,不要直接new,而是把這個new類的動作放在一個工廠的方法中,並返回.有的書上說,變數不要直接持有具體類的引用.

  2、不要讓類繼承具體類,而是繼承抽象類或者實現介面

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