软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的
开放的扩展部分意味着我们应该设计我们的类,以便在需要时可以添加新的功能。封闭的修改部分是指这个新功能应该适合在不修改原类的情况下使用。只有在修复bug的情况下才应该修改类,而不是为了增加新功能。
class CsvExporter {
public function export($data) {
// Implementation...
}
}
class XmlExporter {
public function export($data) {
// Implementation...
}
}
class GenericExporter {
public function exportToFormat($data, $format) {
if ('csv' === $format) {
$exporter = new CsvExporter();
} elseif ('xml' === $format) {
$exporter = new XmlExporter();
} else {
throw new \Exception('Unknown export format!');
}
return $exporter->export($data);
}
}
interface ExporterFactoryInterface {
public function buildForFormat($format);
}
interface ExporterInterface {
public function export($data);
}
class CsvExporter implements ExporterInterface {
public function export($data) {
// Implementation...
}
}
class XmlExporter implements ExporterInterface {
public function export($data) {
// Implementation...
}
}
class ExporterFactory implements ExporterFactoryInterface {
private $factories = array();
public function addExporterFactory($format, callable $factory) {
$this->factories[$format] = $factory;
}
public function buildForFormat($format) {
$factory = $this->factories[$format];
$exporter = $factory(); // the factory is a callable
return $exporter;
}
}
class GenericExporter {
private $exporterFactory;
public function __construct(ExporterFactoryInterface $exporterFactory) {
$this->exporterFactory = $exporterFactory;
}
public function exportToFormat($data, $format) {
$exporter = $this->exporterFactory->buildForFormat($format);
return $exporter->export($data);
}
}
// Client
$exporterFactory = new ExporterFactory();
$exporterFactory->addExporterFactory(
'xml',
function () {
return new XmlExporter();
}
);
$exporterFactory->addExporterFactory(
'csv',
function () {
return new CsvExporter();
}
);
$data = array(/* ... some export data ... */);
$genericExporter = new GenericExporter($exporterFactory);
$csvEncodedData = $genericExporter->exportToFormat($data, 'csv');