我目前正在开发一个允许管理硬件清单的PHP Web界面。在我之前的版本中,我实施了几个API(监控软件/计费软件/部署软件),但由于它们是我公司使用的,我不必担心迎合变化。
重写时,我发现我想要满足每种类型的多种类型,例如2种类型的Billing Sofware,最终用户选择他们想要使用哪种类型。方法应该保持不变,但是它将使用不同的API,不同的功能代码等来获得相同的结果。
我正在研究静态类,工厂模式,单例类,接口/抽象类,但到目前为止,我最不知道哪一个最适合这样的任务?
答案 0 :(得分:0)
查看strategy pattern或template method pattern。
编辑:Voodoo417让我解释如何在这种情况下使用策略。需要明确的是,我的建议旨在将OP指向行为模式的方向而不是创造模式。
根据Billing Software API的复杂程度,解决方案可能是许多不同模式的组合。
另外,请记住,我正在处理用户故事而不是一组实际要求。
首先,我假设OP说
方法应该保持不变,但是它会使用不同的方法 API,不同的功能代码等获得相同的结果。
他实际上说的是他想要将算法(或某些功能)抽象到遵循通用接口的客户端类。这听起来很像战略模式,可能有几个适配器(取决于API)。
我将做出以下假设。
请记住,这是一个令人难以置信的过于简单的解释,其目的是展示使用策略模式。
<?php
class Invoice
{
private $id;
public function __construct($id)
{
$this->id = $id;
}
public function getId()
{
return $this->id;
}
}
interface InvoiceApiInterface
{
public function find($id);
public function create(Invoice $invoice);
}
class InvoiceApi implements InvoiceApiInterface
{
private $invoiceApi;
public function __construct($api)
{
// Should probably have this logic in a factory or something
if ($api instanceof QuickenApi) {
$this->invoiceApi = new QuickenInvoiceApi($api);
} elseif ($api instanceof BillingTrackApi) {
$this->invoiceApi = new BillingTrackInvoiceApi($api);
} else {
throw new \Exception('Invalid api.');
}
}
public function find($id)
{
return $this->invoiceApi->find($id);
}
public function create(Invoice $invoice)
{
return $this->invoiceApi->create($invoice);
}
}
class QuickenInvoiceApi implements InvoiceApiInterface
{
private $api;
public function __construct(QuickenApi $api)
{
$this->api = $api;
}
public function find($id)
{
return $this->api->getInvoice($id);
}
public function create(Invoice $invoice)
{
return $this->api->createNewInvoice($invoice);
}
}
class BillingTrackInvoiceApi implements InvoiceApiInterface
{
private $api;
public function __construct(BillingTrackApi $api)
{
$this->api = $api;
}
public function find($id)
{
return $this->api->find($id);
}
public function create(Invoice $invoice)
{
return $this->api->save($invoice);
}
}
// Existing API's
class QuickenApi
{
public function getInvoice($id)
{
return 'I am a quicken invoice from the quicken API, with an ID of ' . $id;
}
public function createNewInvoice(Invoice $invoice)
{
return 'Successfully created a quicken invoice with an ID of ' . $invoice->getId();
}
}
class BillingTrackApi
{
public function find($id)
{
return 'I am a Billing Track invoice from the billing track API, with an ID of ' . $id;
}
public function save(Invoice $invoice)
{
return 'Successfully created a billing track invoice with an ID of ' . $invoice->getId();
}
}
writeln('Testing Quicken Invoice API');
$quickenApi = new QuickenApi();
$quickenInvoiceApi = new InvoiceApi($quickenApi);
writeln('Test 1: Find a quicken invoice.');
writeln($quickenInvoiceApi->find('SOME-QUICKEN-ID'));
writeln('Test 2: Create a quicken invoice.');
$quickenInvoice = new Invoice('QUICK123');
writeln($quickenInvoiceApi->create($quickenInvoice));
writeln('Testing Billing Track Invoice API');
$billingTrackApi = new BillingTrackApi();
$billingTrackInvoiceApi = new InvoiceApi($billingTrackApi);
writeln('Test 1: Find a billing track invoice.');
writeln($billingTrackInvoiceApi->find('SOME-QUICKEN-ID'));
writeln('Test 2: Create a billing track invoice.');
$billingInvoice = new Invoice('BILLINGTRACK123');
writeln($billingTrackInvoiceApi->create($billingInvoice));
writeln('Test Over.');
function writeln($line_in) {
echo $line_in."<br/>";
}
运行此脚本的结果
Testing Quicken Invoice API
Test 1: Find a quicken invoice.
I am a quicken invoice from the quicken API, with an ID of SOME-QUICKEN-ID
Test 2: Create a quicken invoice.
Successfully created a quicken invoice with an ID of QUICK123
Testing Billing Track Invoice API
Test 1: Find a billing track invoice.
I am a Billing Track invoice from the billing track API, with an ID of SOME-QUICKEN-ID
Test 2: Create a billing track invoice.
Successfully created a billing track invoice with an ID of BILLINGTRACK123
Test Over.
答案 1 :(得分:0)
显然,您必须创建一个通用接口来访问所背后的任何实际软件。
然而,这样做是一般性妄想的经典案例。方法论家们会用可爱的小例子来鼓励你鼓励微笑,但在实际情况下会有许多不愉快的惊喜。
除非两个软件真正共享相同的理念,否则最终可能会编写更多代码来尝试应对差异,而不是为每个软件制作特定版本。开发和测试这样的野兽可能非常困难和耗时。
我很想质疑全球设计,而不是滔滔不绝地提出一个潜在的痛苦解决方案。
为什么一个人想要首先动态地从一个计费系统切换到另一个计费系统?对于给定的客户公司,肯定只有一个计费系统在运行。
您最好为该客户的计费软件编写特定的前端,并将通用接口的工作限制为与其他模块的计费数据流连接。