1. 程式人生 > >設計模式3——抽象工廠模式(abstract-factory)

設計模式3——抽象工廠模式(abstract-factory)

 

一、抽象工廠模式說明

layout title folder permalink categories tags

pattern

Abstract Factory

abstract-factory

/patterns/abstract-factory/

Creational

Java

Gang Of Four

Difficulty-Intermediate

 

佈局 標題 資料夾 永久連結 分類 tags

模式

抽象工廠

abstract-factory

/patterns/abstract-factory/

構建類

Java

四人幫

中級難度

這裡針對分類加以說明,總體來說設計模式分為三大類:

建立型(構建型)模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。

結構型模式,共七種:介面卡模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。

行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、直譯器模式。

之前的觀察者模式屬於行為型模式,而單例模式屬於建立型模式。

其實還有兩類:併發型模式和執行緒池模式。用一個圖片來整體描述一下:

Also known as

也被稱為:

Kit

工具箱 (是不是很神奇的名字,抽象工廠也可以被稱為工具箱類)。

Intent

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

含義

提供一個介面,這個介面能夠建立一個家族相關聯或者相互依賴的物件,而不用具體說明實體類。

注意這是中級難度的哦,得要好好理解和掌握。

Explanation

Real world example

解釋

真實世界的例子

To create a kingdom we need objects with common theme. Elven kingdom needs an Elven king, Elven castle and Elven army whereas Orcish kingdom needs an Orcish king, Orcish castle and Orcish army. There is a dependency between the objects in the kingdom.

 

為了建立一個王國,我們需要一些有共同主題的物件。11個王國需要11個國王,11個城堡和11支軍隊,然而獸人的王國需要一個獸人的國王,獸人的堡壘和獸人的軍隊。王國裡有一種物件之間的依賴關係。(因此一旦看到要構建類似的物件時,可以考慮工廠模式)

In plain words

通俗地講

A factory of factories; a factory that groups the individual but related/dependent factories together without specifying their concrete classes.

 

許多個工廠中的一個,這個工廠能夠將抽象但是相互關聯(依賴)的工廠的相關特徵組合起來,但不用制定實體類。

Wikipedia says

維基百科的說明:

The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes

 

抽象工廠模式提供了一種封裝的一群個別但卻有相同主題的工廠的方式,而這種模式不用指定他們的實體類。

Programmatic Example

程式設計的案例

Translating the kingdom example above. First of all we have some interfaces and implementation for the objects in the kingdom

將上述的王國的案例進行翻譯。首先在王國,我們有一些物件的藉口和實現。

public interface Castle {
  String getDescription();
}
public interface King {
  String getDescription();
}
public interface Army {
  String getDescription();
}

// Elf   精靈
// Elven implementations ->
public class ElfCastle implements Castle {
  static final String DESCRIPTION = "This is the Elven castle!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}
public class ElfKing implements King {
  static final String DESCRIPTION = "This is the Elven king!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}
public class ElfArmy implements Army {
  static final String DESCRIPTION = "This is the Elven Army!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}

// Orcish implementations similarly...

Then we have the abstraction and implementations for the kingdom factory

然後我們有了王國工廠的抽象和實現

public interface KingdomFactory {
  Castle createCastle();
  King createKing();
  Army createArmy();
}

public class ElfKingdomFactory implements KingdomFactory {
  public Castle createCastle() {
    return new ElfCastle();
  }
  public King createKing() {
    return new ElfKing();
  }
  public Army createArmy() {
    return new ElfArmy();
  }
}

public class OrcKingdomFactory implements KingdomFactory {
  public Castle createCastle() {
    return new OrcCastle();
  }
  public King createKing() {
    return new OrcKing();
  }
  public Army createArmy() {
    return new OrcArmy();
  }
}

Now we have our abstract factory that lets us make family of related objects i.e. Elven kingdom factory creates Elven castle, king and army etc.

也就是說(i.e.)現在我們有了抽象工廠,它可以讓我們建立一個相關聯例項家族。11個王國工廠建立了11個城堡、國王和軍隊等。

KingdomFactory factory = new ElfKingdomFactory();
Castle castle = factory.createCastle();
King king = factory.createKing();
Army army = factory.createArmy();

castle.getDescription();  // Output: This is the Elven castle!
king.getDescription(); // Output: This is the Elven king!
army.getDescription(); // Output: This is the Elven Army!

Now, we can design a factory for our different kingdom factories. In this example, we created FactoryMaker, responsible for returning an instance of either ElfKingdomFactory or OrcKingdomFactory.

現在我們可以設計一個針對不同王國工廠的工廠。在這個案例,我們建立了 FactoryMaker,用來返回ElfKingdomFactory或者OrcKingdomFactory的例項。


The client can use FactoryMaker to create the desired concrete factory which, in turn, will produce different concrete objects (Army, King, Castle).

使用者能夠用FactoryMaker 來建立想要的實體工廠,這個實體工廠,反過來,能夠生產出不同的實體物件(軍隊,國王和城堡)


In this example, we also used an enum to parameterize which type of kingdom factory the client will ask for.

在這個例子中,我們也用列舉來進行引數化,這種引數化的方式會根據使用者需要的王國工廠來判斷。

public static class FactoryMaker {

  public enum KingdomType {
    ELF, ORC
  }

  public static KingdomFactory makeFactory(KingdomType type) {
    switch (type) {
      case ELF:
        return new ElfKingdomFactory();
      case ORC:
        return new OrcKingdomFactory();
      default:
        throw new IllegalArgumentException("KingdomType not supported.");
    }
  }
}

public static void main(String[] args) {
  App app = new App();

  LOGGER.info("Elf Kingdom");
  app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
  LOGGER.info(app.getArmy().getDescription());
  LOGGER.info(app.getCastle().getDescription());
  LOGGER.info(app.getKing().getDescription());

  LOGGER.info("Orc Kingdom");
  app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
  -- similar use of the orc factory
}

Applicability

應用性

Use the Abstract Factory pattern when

用抽象工廠模式,當:

  • a system should be independent of how its products are created, composed and represented
  • a system should be configured with one of multiple families of products
  • a family of related product objects is designed to be used together, and you need to enforce this constraint
  • you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations
  • the lifetime of the dependency is conceptually shorter than the lifetime of the consumer.
  • you need a run-time value to construct a particular dependency
  • you want to decide which product to call from a family at runtime.
  • you need to supply one or more parameters only known at run-time before you can resolve a dependency.

 

  • 一個系統應當獨立於產品的建立、組成和表現
  • 一個系統需要配置多個產品系列中的一種
  • 一個相關係列的產品物件被設計來一同使用,而你要做的就是強化這種約束
  • 你想要提供一個產品的類庫,並且你想暴露出來的是他們的介面,而不是他們的實現
  • 依賴的生命週期從概念上來看,比使用者的生命週期短
  • 你需要一個執行時值來構建一個特定的依賴
  • 你想在執行時決定從哪個系列中呼叫產品
  • 在你能夠解析一個依賴之前,你需要提供一個或多個只能在執行時才能知道的引數

 

其實抽象類的好處我覺得,在於能夠將公共成員提取出來,剩下的部分能夠在執行時呼叫確認,增強軟體的靈活性,而抽象工廠則是給工廠類提供了這種靈活性。

Use Cases:

用例:

  • Selecting to call the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime.
  • Unit test case writing becomes much easier

 

  • 在執行時,選擇呼叫適當的FileSystemAcmeService 或  DatabaseAcmeService  或  NetworkAcmeService實現。
  • 單元測試用例的編寫變得更加簡單。

 

Consequences:

結論:

  • Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time.

 

  • java中的依賴注入隱藏了服務類的依賴,這可能會導致執行時的錯誤,而這個錯誤可能在編譯時就被發現了。

Tutorial

教程

Presentations

展示

Real world examples

真實世界的案例

Credits

書籍

二、抽象工廠模式講解分析

1,抽象工廠模式解析

/**
 * 
 * The Abstract Factory pattern provides a way to encapsulate a group of individual factories that have a common theme
 * without specifying their concrete classes. In normal usage, the client software creates a concrete implementation of
 * the abstract factory and then uses the generic interface of the factory to create the concrete objects that are part
 * of the theme. The client does not know (or care) which concrete objects it gets from each of these internal
 * factories, since it uses only the generic interfaces of their products. This pattern separates the details of
 * implementation of a set of objects from their general usage and relies on object composition, as object creation is
 * implemented in methods exposed in the factory interface.

抽象工廠模式提供了一種封裝一系列具有公共主題的個別工廠的方式,但不用指定他們的實體類。通常使用中,客戶軟體建立了一個具體的抽象工廠實現然後用工廠通用的介面構建實體物件,這個物件歸屬於主題的一部分。客戶不知道(或者不關心)哪個實體物件是從哪個內部工廠獲取的,因為它只能使用他們產品的通用介面。這個模式將一系列物件實現的細節和他們通常用法相分離,並且依賴物件組合,如同物件是通過工廠介面暴露出來的方法構建的。

 


 * <p>
 * The essence of the Abstract Factory pattern is a factory interface ({@link KingdomFactory}) and its implementations (
 * {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses both concrete implementations to create a
 * king, a castle and an army.
 * 
 */

抽象工廠模式的本質可以在 一個工廠介面KingdomFactory和它的實現ElfKingdomFactory、OrcKingdomFactory看到。這些例子都使用了實體實現來建立一個國王、一個城堡和一支軍隊。

2,一行一行讀程式碼

首先App 這個類呼叫createKingdom()來設定king、castle、army三個物件,有趣的是它的建立不是直接建立而是通過KingdomFactory的物件來建立,來看這一段的核心程式碼:

app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));

這裡用KingdomType這個類,來判斷需要構建的工廠的例項,而makeFactory方法的返回型別是KingdomFactory,這就是抽象工廠。

其實這個設計模式算相對比較好理解的,它的思路加以學習,其實和服務層先用service的介面然後再實現這樣會比較好是一樣的。為什麼?因為你可能想改實現的方式,改變一些特徵,這時候是很容易進行替換的而不影響原來寫的程式。