According this class diagram, whose purpose is to model the generation of several types of documents:
bigger size available here: https://www.dropbox.com/s/heub3dmh7sznkih/document_generation.png?dl=0
The client code will make use of the DocumentGenerator class, which is a Document factory, describing the type of document needed, and the service (the inspection is optional, only required for dispatch documents).
I'm struggling with the classes coloured in red. If all the insurance companies used the same document models for invoices, estimates, etc, this wouldn't be much of a problem. But there's one company that needs a different dispatch document model to be printed, and this is very likely to happen with more companies, not only with the dispatch but also with the rest of the documents.
Guess what would happen if I specialized each of the document subclasses for each company? It would be a nightmare of code duplication.
Two design patterns (strategy or decorator) might meet my requirement in order to favor composition over inheritance, but I can't figure out how to capture the idea.
Any suggestion is most welcome.
This is a link to the XMI file of this diagram, in case you want to use it: https://www.dropbox.com/s/n1l5ohdnojvvkze/documents_generation.xmi?dl=0
EDIT:
I get an idea of how to do it. Maybe no new class would be necessary. The implementation (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();
The company name and the document type would lead to the proper template to use by the view. I'm still not sure if this is a good solution, since I have hardcoded naming conventions to reach a particular template file.
Any other suggestions??
If you have different requirements you are likely to need different implementations. If you have some general format of the document you can create some superclass covering that document. And if you have different implementations for different companies then you need to either implement completely different Dispatch/Estimate/Invoice classes our you find some generalization (which would enable code-reuse). In any case: different requirements lead to different code. I would not see how this would lead to a nightmare. An alternative is always (though in most cases not possible due to blockheads) it to persuade or rule some common document format.