2015-12-18 18 views
1

我有一個Laravel應用程序,我正在創建一個導入數據的類。數據存儲在大約15個不同的模型中,所以我有一個類來處理每個模型,因爲每個模型都有自己的實現。此外,未來可能會增加更多型號。設計一個類,要求幾個類執行相同的任務

我想在Importer類中有一行代碼,如$importer->import(),然後這個類將接收所有15個實現類,並調用它們的import()方法。

然而,通用$importer->import()方法則是這樣的:

public function __construct(ImporterOne $one, ImporterTwo $two, ImporterThree $three, etc..) 
{ 
    $this->importerOne = $importerOne; 
    $this->importerTwo = $importerTwo; 
    // etc ... 
    $this->importerFifteen = $importerFifteen; 
} 

public function import() 
{ 
    $this->importerOne->import(); 
    $this->importerTwo->importer(); 
    // etc... 
} 

這似乎不是非常好,因爲這個類屆時將有超過15度的關係本質上都做同樣的事情。然後爲了更新這個,我需要在這裏進行添加/刪除依賴關係和import()方法調用。

因此,我的解決方案是將導入器的「註冊」委派給每個實現,而不是讓通用導入器類負責。有效地,一個觀察員的種類。但不是客戶將觀察者附加到主題,而是每個實現都附加到主題上。

use Importer as GenericImporter 

public class importerOne { 

    public function __construct(SomeModel $model, GenericImporter $importer) 
    { 
     $this->importer = $importer; 
     $this->importer->attach($this); 
    } 
} 

// Do the same for each implementation 

// and then the generic importer 

public class Importer { 

    protected $importables = []; 

    public function attach($import_implementation) 
    { 
     array_push($importables, $import_implementation); 
    } 

    public function import() 
    { 
     foreach($this->importables as $importable) 
     { 
      $importable->import(); 
     } 
    } 

} 

這看起來很不錯並且固體。但是,問題是每個實現現在都使用GenericImporter的OWN實例。那麼最好的方法是什麼呢?我是否將Single Generic Importer作爲Singleton實施?此外,爲了我的研究目的,這是否屬於某種設計模式?除了每個觀察者正在註冊之外,它看起來與ObservorPattern類似。

回答

0

你說:

的問題是,每個執行現在使用他們的GenericImporter

OWN 情況下,我不認爲這將是一個問題,因爲GenericImporter只您在實現中注入的依賴關係。此外,你身邊掠過GenericImporter總是相同的對象,因爲它會通過「參考」

編輯

對於下面的評論,被傳遞時,你說:

當通過IoC容器解析依賴項時,它不是通過引用傳遞 。它實例化類

這要看你怎麼做的IOC容器結合的新實例:如果您使用instance(),以這種方式的進口商綁定:

$importer = new Importer(); 
$this->app->instance(Importer::class, $importer); 

那麼同樣的當在您的應用中請求Importer依賴關係時,$importer實例將解析出ioC容器。

END EDIT

無論如何,我將通過添加界面改進設計;是這樣的:

//INTERFACE FOR IMPORTABLES 
interface Importable 
{ 
    public function __construct(Model $model); 
    public function import(); 
} 

//IMPLEMENTATION OF IMPORTABLES 
class importerOne implements Importable 
{ 
    public function __construct(SomeModel $model) 
    { 
    } 

    public function import() 
    { 
     //logic 
    } 
} 

//THE IMPORTER CLASS 
public class Importer 
{  
    protected $importables = []; 

    //attach any Importable 
    public function attach(Importable $import_implementation) 
    { 
     array_push($this->importables, $import_implementation) ; 
    } 

    //trigger Importable::import 
    public function import() 
    { 
     foreach($this->importables as $importable) 
     { 
      $importable->import(); 
     } 
    } 
} 

如果你不想的Importer依賴傳遞到您的進口品的一些具體的原因,你爲什麼不重視來自客戶端的進口品?事情是這樣的:

$importer = new Importer(); 

$importer->attach($importable_1); 
$importer->attach($importable_2); 
//$importer->attach($importable_n); 

$importer->import(); 

這樣,進口商並不需要你通過他們的Importer依賴

取決於你如何建立你的進口品,你也可以考慮構建和存儲在所有這些的陣列和陣列傳遞給進口商:

$importer->attachAll($importables_array); 
+0

感謝您的回答。但是,在Laravel中,通過IoC容器解析依賴關係時,不會通過引用傳遞。它正在實例化該類的一個新實例(在這種情況下爲導入器)。在客戶端代碼中設置它是有道理的,但基本上,我試圖避免這樣的情況:如果需求發生變化並且有更多的實現,我不會不斷修改方法/類/客戶端代碼來追加/刪除實現 – djt

+0

@dtj:第一件事檢查我的編輯上面。對於第二種情況:如果您的客戶端中有多個點需要將不可推薦的數據附加到導入器,則最好使用觀察者的方式 – Moppo

+0

感謝關於該實例的提示,我不知道這一點。我想這是最後一個方面:基本上,所有這些實現都依賴通用導入器類來執行它們的功能。到目前爲止,我仍然需要在代碼中的某個地方實例化每個實現,以觸發Generic Importer的依賴注入到每個實現中。我希望基本上定義所有的實現(可能在服務提供者中),並且當我從某處調用$ importer-> import()時,應用程序知道要收集這些實現並實例化它們。 – djt

0

幾件事...... 1)介意你......自從我接觸PHP以來已經有很多年了......但設計模式是我博士學位的一部分......但是......我建議你嘗試粘貼儘可能接近模式的命名約定(或者至少將類/方法記錄爲它們在一個模式中扮演的角色,因爲我覺得如果你這樣做,你會更容易實現這個功能)

傳統上,Subject對象會保留一組觀察者,它們正在觀察它(你只有1個觀察者,但該模式支持很多),然後調用「notifyObservers()」它循環遍歷所有Observer併爲每個Observer調用「notify()」。您好像試圖發送通知th é'其他方式'。這可能就是爲什麼你會得到'GenericImporter'的多個實例。你想'進口商'來'通知''進口商',但觀察者模式會讓你反過來做,你會希望'進口商'等成爲'主體'和'進口商' '成爲(單)'觀察者'。

這種設計可能會讓你的程序工作方式稍微不自然,但這就是設計模式的方式。你有「觀察員」做得太多。 '觀察者'是一個被動的參與者,當Observed(Subject)類調用「notifyObservers()」時,它會獲取他們的'update(Observable o,Object arg)'方法。如果你這樣設計,你的「觀察者」類可以非常簡單......(就像下面的Java例子)一樣,只要你創建一個實現所有Subjects類擴展的'Observable'功能的基類(importerOne,進口商二等)。

[Observer]實現'notify()'方法/函數。這個'notify()'是Observer被「通知」時調用的內容,而不是「通知」另一端。下面是詳細的評論維基Java示例(我將解釋這一點,因爲我已經很多年沒有碰PHP,而且可以做得更好解釋wiki頁面上的Java例子)

import java.util.Observable; 
import java.util.Scanner; 

// This is the [Subject](Observed) class 
class EventSource extends Observable implements Runnable { 
    public void run() { 
     while (true) { 
      String response = new Scanner(System.in).next(); 
      setChanged(); 
      notifyObservers(response); 
     } 
    } 
    // Notice that EventSource 'extends' [Observable], which means it has... 
    // the following methods available to it also...(among others)... 
    // 
    // addObserver(Observer o) // adds a new Observer 
    // deleteObserver(Observer o) // deletes a specific Observer 
    // notifyObservers(Object arg) // Notifies all observers with some 'arg' 
    // 
    // Notice that 'notifyObservers( )' is the only one called 
} 

import java.util.Observable; 
import static java.lang.System.out; 

class MyApp { 
    public static void main(String[] args) { 
    out.println("Enter Text >"); 

    // This is the [Subject](Observed class/object) 
    EventSource eventSource = new EventSource(); 

    // here the 'Subject' is registering the observer 
    eventSource.addObserver(
     // This is java 8 notation for a new anonymous class 
     // This creates an instance of the [Observer](link below) Interface 
     // The Observer Object only has one method... 
     // update(Observable o, Object arg){} 
     // The below code is the 'implementation' of the... 
     // 'update(Observable o, Object arg)' method 
     // 'obj' is the object that was being observed, 
     // 'arg' is the object passed into 'notifyObservers(Object)'... 
     // from within the [Subject](observed) object. 
     (Observable obj, Object arg) -> 
     { 
      // This code here is what is called when an Observed object 
      // calls 'notifyObservers()' (in this case only '1' observer) 
      out.println("\nReceived response: " + arg); 
     } 
    ); 
} 

Observer JavaDoc

希望這將有助於你調整你的程序使用觀察者模式以更傳統的方式,並允許您在文檔中注意你在做的/ etc什麼。

+0

感謝您的見解,但是我的主題是'GenericImporter'(它是其中之一),並持有的數組和我的Observors其ImportOne進口,ImportTwo,ImportThree(許多)。我的主題調用'import()' - 即notify() - 每個。但是,我的觀察員正在附加主題,而不是附加在客戶端代碼中。因此,每個人都有它自己的實例'GenericImporter' – djt

+0

@dtj你也想要清理一下設計邏輯,讓'importerOne'等所有擴展一些實現Observer通知的父類「ImporterBase」 ) 方法。這樣你的整體設計就更好了。這將允許您更輕鬆地標記您的課程並記下觀察者模式。 – mawalker

+0

謝謝但真的是我問:這是對我的問題最合適的解決方案? – djt

相關問題