Согласно этой диаграмме классов, целью которой является моделирование генерации нескольких типов документов:
большой размер доступен здесь: https://www.dropbox.com/s/heub3dmh7sznkih/document_generation.png?dl=0
Клиентский код будет использовать класс DocumentGenerator, который является фабрикой документов, описывающий тип требуемого документа и службу (проверка является необязательной, требуется только для документов отправки).
Я борюсь с классами, окрашенными в красный цвет. Если бы все страховые компании использовали одни и те же модели документов для счетов-фактур, оценок и т.д., Это не было бы большой проблемой. Но есть одна компания, для которой требуется распечатка другой модели документа отправки, и это может произойти с большим количеством компаний не только с отправкой, но и с остальными документами.
Угадайте, что произойдет, если я специализирую каждый подклассы документов для каждой компании? Это был бы кошмар дублирования кода.
Два шаблона проектирования (стратегия или декоратор) могут соответствовать моим требованиям, чтобы поддержать композицию над наследованием, но я не могу понять, как захватить эту идею.
Любое предложение приветствуется.
Это ссылка на файл XMI этой диаграммы, если вы хотите его использовать: https://www.dropbox.com/s/n1l5ohdnojvvkze/documents_generation.xmi?dl=0
РЕДАКТИРОВАТЬ:
Я понимаю, как это сделать. Может быть, новый класс не нужен. Реализация (PHP):
// DocumentGenerator Class
class DocumentGenerator {
const INVOICE_TYPE = 1;
const ESTIMATE_TYPE = 2;
const DISPATCH_TYPE = 3;
private __construct() {}
public function getInstance($type, Service $service)
{
switch($type) {
case self::ESTIMATE_TYPE:
$document = new Estimate($service);
break;
case self::DISPATCH_TYPE:
$document = new Dispatch($service);
break;
default:
case self::INVOICE_TYPE:
$document = new Invoice($service);
}
return $document;
}
}
// Document Class
abstract class Document {
protected $service;
public function __construct(Service $service)
{
$this->service = $service;
}
abstract protected function show();
// ....
}
// Invoice Class
class Invoice extends Document {
const PATH_SEGMENT = 'invoice';
public function show()
{
// the key point
$this->view->setPath(self::PATH_SEGMENT . '/' . $service->getCompanyName());
$this->view->create();
}
// ...
}
// creating an invoice, no matter the company
$document = DocumentGenerator::getInstance(DocumentGenerator::INVOICE_TYPE, $service);
$document->show();
Название компании и тип документа приведут к правильному шаблону для использования в представлении. Я все еще не уверен, что это хорошее решение, так как у меня есть жестко закодированные соглашения об именах для доступа к определенному файлу шаблона.
Любые другие предложения?
Если у вас разные требования, вам, вероятно, понадобятся разные реализации. Если у вас есть общий формат документа, вы можете создать некоторый суперкласс, покрывающий этот документ. И если у вас разные реализации для разных компаний, тогда вам нужно либо реализовать совершенно разные классы Dispatch/Estimate/Invoice, и вы найдете некоторое обобщение (что позволит использовать повторное использование кода). В любом случае: разные требования приводят к разному коду. Я не увижу, как это приведет к кошмару. Альтернатива всегда (хотя в большинстве случаев невозможна из-за болванов), чтобы убедить или изменить какой-то общий формат документа.