Factory Method(工廠方法)-工廠模式(創(chuàng)建型)

1.概述

工廠設計模式是一種創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式。在工廠模式中,我們創(chuàng)建對象時不會對客戶端暴露創(chuàng)建邏輯,并且是通過使用一個共同的接口來指向新創(chuàng)建的對象。

1.1針對的問題

在面向?qū)ο缶幊讨?,最常用的方法是new一個操作符產(chǎn)生一個對象實例,new對象操作符就是用來構造對象實例的,但是在一些情況下,new操作符直接生成對象會帶來一些問題,舉例說,許多類型對象的創(chuàng)建都需要一系列的步驟,可能需要計算或取得對象的初始設置,選擇生成哪個子對象實例,或者在生成需要的對象之前必須先生成一些輔助功能的對象,這些情況下,對象的建立就是一個過程,不僅是一個操作。

1.2 分析

實例化一個對象sample 一般會想到的方法是通過構造器來創(chuàng)建$sample =new sample();但是在實際情況下最好不要這樣做,如果sample類的在實例化的時候需要初始化參數(shù)而這些參數(shù)需要別的類的信息,這樣你new的話會增加你代碼的耦合度,不利于維護。所以我們就需要將創(chuàng)建實例的工作和使用使用實例的工作分開,即:使用工廠方法創(chuàng)建實例的工作封裝起來。這樣我們在需要調(diào)用對象的時候就不需要關心那些復雜的實例化問題。

1.3. 工廠模式類型

工廠模式主要是為創(chuàng)建對象提供過渡接口,以便將創(chuàng)建對象的具體過程屏蔽隔離起來,達到靈活性的目的。
工廠模式一共三類
(1)簡單工廠模式: 允許接口創(chuàng)建對象,但不會暴露對象的創(chuàng)建邏輯。
(2)工廠方法模式:允許接口創(chuàng)建對象,但使用哪個類來創(chuàng)建對象,則是交由子類決定的。
(3)抽象工廠模式:抽象工廠是一個能夠創(chuàng)建一系列相關的對象而無需指定/公開其具體類的接口。該模式能夠提供其他工廠的對象,在其內(nèi)部創(chuàng)建其他對象。

2.工廠模式特征

2.1簡單工廠模式

2.1.1角色組成

1.抽象工廠類
2.抽象產(chǎn)品類
3.具體產(chǎn)品類
簡單工廠模式中有抽象產(chǎn)品類:用來定義具體產(chǎn)品的共有屬性,工廠類則負責生產(chǎn)具體產(chǎn)品。
直接看代碼:定義一個抽象產(chǎn)品類形狀類Shape

abstract class Shape{
    abstract public  shape();
}

定義具體產(chǎn)品:

class Circle extends Shape{
    public function shape(){
        echo '圓形';
    }
}

class Rectangle extends Shape{
    public function shape(){
        echo '矩形';
    }
}

class Triangle  extends Shape{
    public function shape(){
        echo '三角形';
    }
}

定義一個工廠生產(chǎn)具體產(chǎn)品

class ShapeFactory{
  public static function getShape($sh)
  {
    switch($sh){
      case '圓形':
        return new Circle();
        break;
      case '矩形':
        return new Rectanle();
        break;
      case '三角形':
        return new Triangle();
        break;
      default:
        echo "該形狀不存在 \n";
        break;
    }
  }
}
//調(diào)用
ShapeFactory::getShape('圓形');

從簡單工廠中我們可以看出使用一個靜態(tài)方法將實例化的創(chuàng)建和使用分離開。我們只需要調(diào)用方法傳遞參數(shù)就可以獲得我們需要的對象。
缺點:我們不難看出如果我們想要增加一個形狀類的產(chǎn)品不僅需要添加一個導出類而且我們必須要修改靜態(tài)方法getshape,這樣就違背了開閉原則(對于擴展是開放的,對于修改是封閉的)
這時我們就可以想我們是不是可以將工廠也抽象出來?讓具體工廠來負責創(chuàng)建具體產(chǎn)品對象,就上面的例子我們可以創(chuàng)建一個圓形的具體工廠讓他只負責創(chuàng)建圓形產(chǎn)品對象,這樣當我們想要增加一個產(chǎn)品的時候我們就只需要增加對應的工廠就行了,不需要修改其他東西。接下來我們說說工廠模式

2.2工廠方法模式

工廠方法模式是對簡單工廠模式進一步的解耦,因為在工廠方法模式中是一個子類對應一個工廠類,而這些工廠類都實現(xiàn)于一個抽象接口。這相當于是把原本會因為業(yè)務代碼而龐大的簡單工廠類,拆分成了一個個的工廠類,這樣代碼就不會都耦合在同一個類里了。

2.2.1 角色組成

1)抽象工廠角色: 這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現(xiàn)的接口或者必須繼承的父類。
2)具體工廠角色:它含有和具體業(yè)務邏輯有關的代碼。由應用程序調(diào)用以創(chuàng)建對應的具體產(chǎn)品的對象。
3)抽象產(chǎn)品角色:它是具體產(chǎn)品繼承的父類或者是實現(xiàn)的接口。
4)具體產(chǎn)品角色:具體工廠角色所創(chuàng)建的對象就是此角色的實例。

2.2.2實現(xiàn)

  1. 首先定義一個工廠接口:
interface Factory{
    public function createOperation();
}
  1. 然后是具體的工廠類:
// 加法類工廠
class AddFactory implements Factory{
    public function createOperation() {
        echo "加法運算~\n";
        return new Add();
    }
}
 
// 減法類工廠
class SubFactory implements Factory{
    public function createOperation() {
        echo "減法運算~\n";
        return new Sub();
    }
}
...
  1. 運算類
//計算抽象類
interface Operation {
    public function getResult($numberA,$numberB);
}

class Add implements Operation{
    // 加法計算
    public function getResult($numberA, $numberB) {
        return $numberA + $numberB;
    }
}

class Sub implements Operation{
    // 減法計算
    public function getResult($numberA, $numberB) {
        return $numberA-$numberB;
    }
}
  1. 客戶端代碼:
class Client{
    public function run(){
        $farm = "Factory";
        $type = "Add";
        $className = $type.$farm;
        $addFactory = new AddFactory();
        $subFactory = new SubFactory();

        echo $addFactory->createOperation(1,1);
        echo $subFactory->createOperation(1,1);
    }
}

2.2.3分析

工廠模式中,要增加產(chǎn)品類時也要相應地增加工廠類,客戶端的代碼也增加了不少。工廠方法把簡單工廠的內(nèi)部邏輯判斷轉(zhuǎn)移到了客戶端代碼來進行。

你想要加功能,本來是改工廠類的,而現(xiàn)在是修改客戶端。而且各個不同功能的實例對象的創(chuàng)建代碼,也沒有耦合在同一個工廠類里,這也是工廠方法模式對簡單工廠模式解耦的一個體現(xiàn)。工廠方法模式克服了簡單工廠會違背開-閉原則的缺點,又保持了封裝對象創(chuàng)建過程的優(yōu)點。

但工廠方法模式的缺點是每增加一個產(chǎn)品類,就需要增加一個對應的工廠類,增加了額外的開發(fā)量。

2.3抽象工廠模式 生產(chǎn)工廠的工廠 供應鏈

抽象工廠模式是工廠方法模式的升級版本,它用來創(chuàng)建一組相關或者相互依賴的對象。

抽象工廠模式提供一個創(chuàng)建一系列相關或者相互依賴對象的接口,而無需指定他們具體的類。就是一個工廠里放一些相關的類,使工廠數(shù)減少。

最大的好處便是易于交換產(chǎn)品系列,其次是讓具體的創(chuàng)建實例過程與客戶端分離,客戶端通過他們的抽象接口操縱實例,產(chǎn)品的具體類名也被具體工廠的實現(xiàn)分離。不會出現(xiàn)在客戶代碼中

2.3.1場景:對數(shù)據(jù)庫中的表進行修改

  1. 我們現(xiàn)在要對mysql/oracle數(shù)據(jù)庫中的User表進行操作,User表定義如下:
public class User {
    private $uid;
    private $uname;
 
    public int getUid() {
        return $uid;
    }
 
    public function setUid($uid) {
        $this->uid = $uid;
    }
 
    public function getUname() {
        return $uname;
    }
 
    public function setUname($uname) {
        $this->uname = $uname;
    }
}
  1. 接下來我們定義一個對User進行操作的接口:
interface IUser {
    public function insert($user);
    public function getUser($uid);
}
  1. 實現(xiàn)一個對mysql中User進行操作的類:
class mysqlUser implements IUser{
 
    public function insert($user){
        print("在mysql中的user表中插入一條元素");
    }
 
    public function getUser($id){
        print("在mysql中的user表得到id為".$id."的一條數(shù)據(jù)");
        return null;
    }
}

實現(xiàn)對oracle中User進行操作的類:

class oracleUser implements IUser{

    public function insert($user) {
        println("在oracle中的user表中插入一條元素");
    }
 
  
    public function getUser($uid) {
        print("在oracle中的user表得到id為".$uid."的一條數(shù)據(jù)");
        return null;
    }
}
  1. 接下來定義一個工廠接口,用于生產(chǎn)訪問User表的對象:
interface sqlFactory {
    public function createUser();     //用于訪問User表的對象
}
  1. 生產(chǎn)mysqlUser對象的mysql工廠類:
class mysqlFactory implements sqlFactory {
    public function createUser() {
        return new mysqlUser();  //訪問mysql中User表的對象
    }
}

生成oracleUser對象的oracle工廠類:

class oracleFactory implements sqlFactory {
    public IUser createUser() {
        return new oracleUser();   //訪問oracle中User表的對象
    }
}
  1. 最后用戶測試類如下:
class test_abstractFactory {
    public static function main($args) {
        $factory1 = new mysqlFactory();
        $userOperator = $factory1.createUser();
        $userOperator.getUser(1);
        $userOperator.insert(new User());
    }
}

結(jié)果為:
在mysql中的user表得到id為1的一條數(shù)據(jù)
在mysql中的user表中插入一條元素

2.3.2 分析

抽象工廠模式是工廠方法模式的升級版本,他用來創(chuàng)建一組相關或者相互依賴的對象。他與工廠方法模式的區(qū)別就在于,工廠方法模式針對的是一個產(chǎn)品等級結(jié)構;而抽象工廠模式則是針對的多個產(chǎn)品等級結(jié)構。在編程中,通常一個產(chǎn)品結(jié)構,表現(xiàn)為一個接口或者抽象類,也就是說,工廠方法模式提供的所有產(chǎn)品都是衍生自同一個接口或抽象類,而抽象工廠模式所提供的產(chǎn)品則是衍生自不同的接口或抽象類。

總結(jié)

工廠具有下列優(yōu)點:松耦合,即對象的創(chuàng)建可以獨立于類的實現(xiàn);客戶端無需了解創(chuàng)建對象的類,但是照樣可以使用它來創(chuàng)建對象。它只需要知道需要傳遞的接口、方法和參數(shù),就能夠創(chuàng)建 所需類型的對象了。這簡化了客戶端的實現(xiàn);可以輕松地在工廠中添加其他類來創(chuàng)建其他類型的對象,而這無需更改客戶端代碼。最簡單的情況下,客戶端只需要傳遞一個參數(shù)就可以了;工廠還可以重用現(xiàn)有對象。但是,如果客戶端直接創(chuàng)建對象的化,總是創(chuàng)建一個新對象。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容