在複雜的軟體系統架構中,將原來雜亂無章的組件加以分門別類,然後從中取出性質相似與功能相近的物件,使其集中群聚,就能夠大幅地簡化程式系統組件的複雜度。而 Abstract Factory 模式,正是用來協助程式設計者將物件分門別類與集中管理的好方法。
Abstract Factory 的「工廠」,與 Factory Method 的「工廠」目的相同,同樣屬於「生成模式」的分類,都是用來產生出物件成品的製造者。對於設計模式的入門者來說,很容易將 Factory Method 模式與 Abstract Factory 模式兩者的使用目的以及使用時機搞混;雖然都是屬於工廠類型的作業模式,然而 Abstract Factory 與 Factory Method 的不同之處在於,抽象工廠模式是將一組性質相關或相依的物件,放在同一個工廠裡生產。例如對於食品工廠來說,能夠生產的包含飲料、零食與泡麵三項食品類的產品;而皮件工廠,則能夠生產出皮包、皮帶與皮鞋等皮製產品。也就是在一個工廠之內有數個不同的生產線,能夠同時進行不同成品的生產作業。在實際程式系統的應用中,可以說 Abstract Factory 經常是一堆 Factory Method 的組合。
以 Abstract Factory 設計模式的 UML 結構圖來看,根據《物件導向設計模式》(Design Patterns) 書中所述,其中定義了參與抽象工廠模式的幾個角色:
- AbstractFactory:此介面宣告出可生成各抽象成品物件的操作。
- ConcreteFactory:具體實作出可建構具象成品物件的操作。
- AbstractProduct:宣告某成品物件類型之介面。
- ConcreteProduct:是 ConcreteFactory 所建構的成品物件;也是 AbstractFactory 介面的具象實作。
- Client:只觸及 AbstractFactory 和 AbstractProduct 兩抽象類別所訂之介面。
與 Factory Method 的結構相似,首先由 AbstractFactory 宣告出創建物件的抽象介面,然後再由繼承而來的子類別 ConcreteFactory 具體實作出對應於各實體成品的操作細節。AbstractProduct 與 ConcreteProduct 之間的關係亦然類似;AbstractProduct 屬於抽象基底產品,而 ConcreteProduct 是衍生而來的實體產品。對於系統外部的使用者 Client 來說,無須瞭解 ConcreteFactory 與 ConcreteProduct 的實作細節,僅需接觸 AbstractFactory 與 AbstractProduct 兩者的介面,就能夠產生出相對應的實體成品。
下圖為AbstractFactory的類別圖:
圖中AbstractFactory、Part指的是,物件必須具有AbstractFactory、Part所定義之公開協定,而非專指Java中的interface定義。對於靜態語言來說,例如Java,必須使用型態來宣告變數,因此根據需求,可以使用interfact或abstract class來定義AbstractFactory、Part所定義之公開協定。
Sample 1:
圖中AbstractFactory、Part指的是,物件必須具有AbstractFactory、Part所定義之公開協定,而非專指Java中的interface定義。對於靜態語言來說,例如Java,必須使用型態來宣告變數,因此根據需求,可以使用interfact或abstract class來定義AbstractFactory、Part所定義之公開協定。
Sample 1:
AbstractBookFactory.php
//copyright Lawrence Truett and FluffyCat.com 2007, all rights reserved abstract class AbstractBookFactory { abstract function makePHPBook(); abstract function makeMySQLBook(); }
download source, use right-click and "Save Target As..." to save with a .php extension.
OReillyBookFactory.php
//copyright Lawrence Truett and FluffyCat.com 2007, all rights reserved include_once('AbstractMySQLBook.php'); class OReillyMySQLBook extends AbstractMySQLBook { private $author; private $title; function __construct() { $this->author = 'George Reese, Randy Jay Yarger, and Tim King'; $this->title = 'Managing and Using MySQL'; } function getAuthor() {return $this->author;} function getTitle() {return $this->title;} }
download source, use right-click and "Save Target As..." to save with a .php extension.
SamsBookFactory.php
//copyright Lawrence Truett and FluffyCat.com 2005, all rights reserved include_once('AbstractBookFactory.php'); include_once('SamsPHPBook.php'); include_once('SamsMySQLBook.php'); class SamsBookFactory extends AbstractBookFactory { private $context = "Sams"; function makePHPBook() {return new SamsPHPBook;} function makeMySQLBook() {return new SamsMySQLBook;} }
download source, use right-click and "Save Target As..." to save with a .php extension.
AbstractBook.php
//copyright Lawrence Truett and FluffyCat.com 2007, all rights reserved abstract class AbstractBook { abstract function getAuthor(); abstract function getTitle(); }
Sample 2:
AbstractMySQLBook.php
//copyright Lawrence Truett and FluffyCat.com 2007, all rights reserved include_once('AbstractBook.php'); abstract class AbstractMySQLBook { private $subject = "MySQL"; }
download source, use right-click and "Save Target As..." to save with a .php extension.
OReillyMySQLBook.php
//copyright Lawrence Truett and FluffyCat.com 2007, all rights reserved include_once('AbstractMySQLBook.php'); class OReillyMySQLBook extends AbstractMySQLBook { private $author; private $title; function __construct() { $this->author = 'George Reese, Randy Jay Yarger, and Tim King'; $this->title = 'Managing and Using MySQL'; } function getAuthor() {return $this->author;} function getTitle() {return $this->title;} }
download source, use right-click and "Save Target As..." to save with a .php extension.
SamsMySQLBook.php
//copyright Lawrence Truett and FluffyCat.com 2007, all rights reserved include_once('AbstractMySQLBook.php'); class SamsMySQLBook extends AbstractMySQLBook { private $author; private $title; function __construct() { $this->author = 'Paul Dubois'; $this->title = 'MySQL, 3rd Edition'; } function getAuthor() {return $this->author;} function getTitle() {return $this->title;} }
download source, use right-click and "Save Target As..." to save with a .php extension.
AbstractPHPBook.php
//copyright Lawrence Truett and FluffyCat.com 2007, all rights reserved include_once('AbstractBook.php'); abstract class AbstractPHPBook { private $subject = "PHP"; }
download source, use right-click and "Save Target As..." to save with a .php extension.
OReillyPHPBook.php
//copyright Lawrence Truett and FluffyCat.com 2007, all rights reserved include_once('AbstractPHPBook.php'); class OReillyPHPBook extends AbstractPHPBook { private $author; private $title; private static $oddOrEven = 'odd'; function __construct() { //alternate between 2 books if ('odd' == self::$oddOrEven) { $this->author = 'Rasmus Lerdorf and Kevin Tatroe'; $this->title = 'Programming PHP'; self::$oddOrEven = 'even'; } else { $this->author = 'David Sklar and Adam Trachtenberg'; $this->title = 'PHP Cookbook'; self::$oddOrEven = 'odd'; } } function getAuthor() {return $this->author;} function getTitle() {return $this->title;} }
download source, use right-click and "Save Target As..." to save with a .php extension.
SamsPHPBook.php
//copyright Lawrence Truett and FluffyCat.com 2007, all rights reserved include_once('AbstractPHPBook.php'); class SamsPHPBook extends AbstractPHPBook { private $author; private $title; function __construct() { //alternate randomly between 2 books mt_srand((double)microtime()*10000000); $rand_num = mt_rand(0,1); if (1 > $rand_num) { $this->author = 'George Schlossnagle'; $this->title = 'Advanced PHP Programming'; } else { $this->author = 'Christian Wenz'; $this->title = 'PHP Phrasebook'; } } function getAuthor() {return $this->author;} function getTitle() {return $this->title;} }
download source, use right-click and "Save Target As..." to save with a .php extension.
testAbstractFactory.php
//copyright Lawrence Truett and FluffyCat.com 2005, all rights reserved include_once('OReillyBookFactory.php'); include_once('SamsBookFactory.php'); echo tagins("html"); echo tagins("head"); echo tagins("/head"); echo tagins("body"); echo "BEGIN TESTING ABSTRACT FACTORY PATTERN"; echo tagins("br").tagins("br"); echo 'testing OReillyBookFactory'.tagins("br"); $bookFactoryInstance = new OReillyBookFactory; testConcreteFactory($bookFactoryInstance); echo tagins("br"); echo 'testing SamsBookFactory'.tagins("br"); $bookFactoryInstance = new SamsBookFactory; testConcreteFactory($bookFactoryInstance); echo tagins("br"); echo "END TESTING ABSTRACT FACTORY PATTERN"; echo tagins("br"); echo tagins("/body"); echo tagins("/html"); function testConcreteFactory($bookFactoryInstance) { $phpBookOne = $bookFactoryInstance->makePHPBook(); echo 'first php Author: '. $phpBookOne->getAuthor().tagins("br"); echo 'first php Title: '. $phpBookOne->getTitle().tagins("br"); $phpBookTwo = $bookFactoryInstance->makePHPBook(); echo 'second php Author: '. $phpBookTwo->getAuthor().tagins("br"); echo 'second php Title: '. $phpBookTwo->getTitle().tagins("br"); $mySqlBook = $bookFactoryInstance->makeMySQLBook(); echo 'MySQL Author: '. $mySqlBook->getAuthor().tagins("br"); echo 'MySQL Title: '. $mySqlBook->getTitle().tagins("br"); } //doing this so code can be displayed without breaks function tagins($stuffing) { return "<".$stuffing.">"; }
download source, use right-click and "Save Target As..." to save with a .php extension.
output of testAbstractFactory.php
BEGIN TESTING ABSTRACT FACTORY PATTERN testing OReillyBookFactory first php Author: Rasmus Lerdorf and Kevin Tatroe first php Title: Programming PHP second php Author: David Sklar and Adam Trachtenberg second php Title: PHP Cookbook MySQL Author: George Reese, Randy Jay Yarger, and Tim King MySQL Title: Managing and Using MySQL testing SamsBookFactory first php Author: Christian Wenz first php Title: PHP Phrasebook second php Author: George Schlossnagle second php Title: Advanced PHP Programming MySQL Author: Paul Dubois MySQL Title: MySQL, 3rd Edition END TESTING ABSTRACT FACTORY PATTERN
沒有留言:
張貼留言