我有一个Laravel应用程序,我正在创建一个导入数据的类。数据存储在大约15个不同的模型中,因此我有一个Class来处理每个模型,因为每个模型都有自己的实现。此外,未来可能会添加更多型号。
我想在$importer->import()
类中使用一行代码Importer
,然后获取所有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()
方法调用。
所以我的解决方案是委托注册'每个实现的导入程序,而不是让Generic Importer类负责。实际上,一个观察者的种类。但是,不是客户端将Observer附加到Subject,而是每个实现都将自己附加到Subject。
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实例。那么最好的方法是什么呢?我是否将Generic Importer实现为Singleton?另外,为了我的研究目的,这是否属于某种设计模式?它似乎与ObservorPattern相似,只是每个Observer都在注册。
答案 0 :(得分:0)
很少有事情...... 1)请注意......自从我接触PHP以来已经有好几年......但设计模式是我博士学位的一部分......但是......我建议你尽量坚持下去尽可能接近模式的命名约定(或者至少将类/方法记录为模式中的角色。因为我觉得如果你这样做,你将更容易实现它。
您实际上似乎正在实施-inverse- observer pattern。传统上,Subject对象保持一组观察者“正在”观察它(你只有一个观察者,但模式支持很多)。然后调用“notifyObservers()”循环遍历所有Observer并为每个Observer调用'notify()'。您似乎试图以“其他方式”发送通知。这可能是您获得'GenericImporter'的多个实例的原因。你希望'importerOne''通知''导入者',但Observer模式会让你反过来做,你会希望'importerOne'等是'主题'和'进口商' '成为(单一)'观察者'。
这种设计在您希望程序运行的方式上可能不那么自然,但这就是模式的设计方式。你有“观察者”做得太多了。 'Observer'是一个被动的actor,只是在Observed(Subject)类调用“notifyObservers()”时调用它们的'update(Observable o,Object arg)'方法。如果你这样设计它,你的“观察者”类可以非常简单......(如下面的Java示例)只要你创建一个实现所有Subjects类扩展的'Observable'功能的基类(importerOne, importerTwo等。)
[Observer]实现'notify()'方法/函数。这个'notify()'是Observer被'通知'时调用的,而不是它想要'通知'另一端。这是带有详细注释的wiki Java示例(我将解释这个,因为我多年没有触及PHP,并且可以更好地解释维基页面上的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);
}
);
}
希望这可以帮助您调整程序以更传统的方式使用观察者模式,并允许您在文档中记录您正在做什么/等。
答案 1 :(得分:0)
你这么说:
问题是每个实现现在都在使用他们的OWN GenericImporter的实例
我不认为这会是一个问题,因为GenericImporter
只是您在实现中注入的依赖项。此外,您传递的GenericImporter
始终是同一个对象,因为它将通过'reference'传递
修改强>
关于以下评论,当你说:
当依赖关系通过IoC容器解决时,它不是 通过引用传递。它正在实例化该类的新实例
这取决于你在ioC容器中如何进行绑定:如果你使用instance()
,以这种方式绑定Importer:
$importer = new Importer();
$this->app->instance( Importer::class, $importer );
然后,当您的应用程序中请求$importer
依赖项时,将从ioC容器中解析出相同的Importer
实例。
结束编辑
无论如何,我会通过添加界面来改进设计;像这样的东西:
//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
依赖关系
根据您构建importable的方式,您还可以考虑在数组中构建和存储所有这些内容并将数组传递给Importer:
$importer->attachAll( $importables_array );