5. 設計模式-工廠模式

設計模式-工廠模式

工廠模式適合場景:

  • 如果你和你對象去飯館喫飯,如果沒有服務員(工廠類),點菜怎麼點?

  • 餐館的菜單方便客人更改嗎?

  • 凡是出現了大量的產品需要創建,並且具有共同的接口時,可以通過工廠模式進行創建。

1. 工廠模式在 JDK-Calendar 的應用

工廠方法模式

// 第一步創建Calendar對象 
Calendar calendar = Calendar.getInstance();

// 第二步調用getInstance()方法(抽象類Calendar)
public static Calendar getInstance(){
    return createCalendar(
        TimeZone.getDefault(), 
        Locale.getDefault(Locale.Category.FORMAT));
}

// 第三步創建對象
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;
}

2. 簡單工廠模式

  1. 建立一個工廠類,對實現了同一接口的一些類進行實例的創建。
  2. 簡單工廠把實例化的操作單獨放到一個類中,這個類就成爲簡單工廠類,讓簡單工廠類來決定應該用哪個具體子類來實例化。
//定義一個接口規範
public interface Sender {
  public void Send();
}

//建造一個實現類,並且實現定義的接口
public class MailSender implements Sender{
    public void Send() {
        System.out.println("this is mailsender!");
    }
}

//建造一個實現類,並且實現定義的接口
public class SmsSender implements Sender {
    public void Send() {
        System.out.println("this is sms sender!");
    }
} 

//建工廠類
public class SendFactory {
    public Sender produce(String type){
        if("mail".equals(type)){
            return new MailSender();
        }else if("sms".equals(type)){
            return new SmsSender();
        }else{
            System.out.println("請輸入正確的類型!");
            return null;
        }
    }
    
}

//進行測試
public class FactoryTest {

        public static void main(String[] args) {
            //創建工廠類對象
            SendFactory factory = new SendFactory();

            //通過工廠類來創建SmsSender對象,
            //SmsSender smsSender = factory.produce("sms");
            Sender sender = factory.produce("sms");

            //smsSender.Send();
            sender.Send();
        }
}

專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。它又稱爲靜態工廠方法模式。體現在下面的代碼中。

//創建一個工廠類
public class SendFactory {  
      
    public static Sender produceMail(){  
        return new MailSender();  
    }  

    public static Sender produceSms(){  
        return new SmsSender();  
    }  
}  


public class FactoryTest {  
  
    public static void main(String[] args) {
        
        Sender sender = SendFactory.produceMail(); 
        
        sender.Send();  
    }  
}  

3. 工廠方法模式(Factory Method)

  1. 在簡單工廠中,創建對象的是另一個類,而在工廠方法中,是由子類來創建對象。
  2. 因爲工廠方法模式把具體產品的創建推遲到工廠類的子類(具體工廠)中,此時工廠類不再負責所有產品的創建,而只是給出具體工廠必須實現的接口,這樣工廠方法模式在添加新產品的時候就不修改工廠類邏輯而是添加新的工廠子類,符合開放封閉原則,克服了簡單工廠模式中缺點。
//  1. 創建抽象工廠類
abstract class Factory{
    public abstract Product Manufacture();
}

// 2. 創建抽象產品類
abstract class Product{
    public abstract void Show();
}

// 3. 創建具體產品類(繼承抽象產品類), 定義生產的具體產品;
//具體產品A類
class  ProductA extends  Product{
    @Override
    public void Show() {
        System.out.println("生產出了產品A");
    }
}
 
//具體產品B類
class  ProductB extends  Product{
 
    @Override
    public void Show() {
        System.out.println("生產出了產品B");
    }
}
// 4. 創建具體工廠類(繼承抽象工廠類),定義創建對應具體產品實例的方法;
//工廠A類 - 生產A類產品
class  FactoryA extends Factory{
    @Override
    public Product Manufacture() {
        return new ProductA();
    }
}
 
//工廠B類 - 生產B類產品
class  FactoryB extends Factory{
    @Override
    public Product Manufacture() {
        return new ProductB();
    }
}

// 5. 外界通過調用具體工廠類的方法,從而創建不同具體產品類的實
//生產工作流程
public class FactoryPattern {
    public static void main(String[] args){
        //客戶要產品A
        FactoryA mFactoryA = new FactoryA();
        mFactoryA.Manufacture().Show();
 
        //客戶要產品B
        FactoryB mFactoryB = new FactoryB();
        mFactoryB.Manufacture().Show();
    }
}

3. 抽象工廠模式(Abstract Factory)

抽象工廠模式是對工廠方法模式的進一步改進,在工廠方法模式中,工廠的核心類只能產出一種產品。而在抽象工廠模式中,可以創建一組相關聯的產品。

一系列產品類

這裏舉兩個例子:蛋糕的製作和果汁的製作;

/**
 *製作水果汁接口
 */
public interface JuiceProduct {
    void make();
}

/**
*製作蛋糕的接口
*/
public interface CakeProduct {
	void cooking();
}


/**
 * 製作蘋果汁
 */
public class AppleJuiceProduct implements JuiceProduct {
    @Override
    public void make() {
        System.out.println("正在製作蘋果汁>>>");
    }
}
/**
 * 製作梨汁
 */
public class PearJuiceProduct implements JuiceProduct {
    @Override
    public void make() {
        System.out.println("正在製作梨汁>>>");
    }
}

/**
 * 製作香蕉汁
 */
public class BananaJuiceProduct implements JuiceProduct {
    @Override
    public void make() {
        System.out.println("正在製作香蕉汁>>>");
    }
}

public class CheeseCakeProduct implements CakeProduct {
    @Override
    public void cooking() {
        System.out.println("正在烹飪芝士蛋糕>>>");
    }
}

一系列工廠類
/**
 * 製作套餐工廠
 */
public interface SetMealFactory {

    //生產蛋糕
    CakeProduct productCake();

    //生產果汁
    JuiceProduct productJuice();

}

/**
 * A套餐生產工廠
 */
public class ASetMealFactory implements SetMealFactory{

    //生產芝士蛋糕
    @Override
    public CakeProduct productCake() {
        return new CheeseCakeProduct();
    }

    //生產蘋果汁
    @Override
    public JuiceProduct productJuice() {
        return new AppleJuiceProduct();
    }
}

通過抽象工廠模式和工廠方法模式區別這篇博客的類圖可以更通透的理解抽象工廠模式。

5. 工廠模式小結

工廠模式的意義:

  1. 將實例化對象的代碼提取出來,放到一個類中統一管理和維護,達到和主項目的依賴關係的解耦。從而提高項目的擴展和維護性。

三種工廠模式:

  1. 簡單工廠模式
  2. 工廠方法模式
  3. 抽象工廠模式

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章