开放/封闭原则与扩展一些代码以添加功能有关,而无需修改类的核心行为(即不编辑源代码)。你的类保持它自己的内部,并提供清晰的公共接口来与它们交互。从这个角度来看,不,你没有打破开放/封闭原则。 至少不是表面价值。
但是,话虽如此,我也从您的问题中得到印象,您想知道为您的私人 $codeMap 数组设置一个设置器是否违反了原则。它不是直接的,但是如果另一个开发人员想要更精细地访问$codeMap 数组,那么该实现也很有吸引力。基本上,即时更新此数组的唯一方法是清除它并使用setCodeMap() 重置它。您没有提供将单个代码添加到地图的机制。一旦您发现自己需要更精细地访问此地图,您也会发现自己违反了开放/封闭原则。
考虑到这一点,假设另一个开发人员正在使用您的代码,并且 $codeMap 数组有 20 或 30 个元素;他们必须破解您的核心代码,以便更好地访问该数组。由于无法添加单个代码,因此他们必须创建一个新数组以传递给setCodeMap(),该数组由当前$codeMap 数组以及他们希望添加的任何其他元素组成。在不打开My_ThingFactory 并添加类似以下内容的情况下,没有其他方法(除了对原始数组进行硬编码):
public function getCodeMap()
{
return $this->codeMap;
}
然后在他们的扩展类中,他们可以执行以下操作:
class AnotherThingFactory extends My_ThingFactory
{
public function addCodes(array $newCodes)
{
$this->setCodeMap(array_merge($this->getCodeMap(), $newCodes));
}
}
但同样,这只能通过进入您的课程并在之前添加所需的功能来实现,这确实打破了打开/关闭原则。您也可以通过简单地创建$codeMap 属性protected 来纠正这个问题,然后扩展类可以在不破解您的代码的情况下完成他们需要做的事情。扩展类也有责任确保他们正确地操作它。
所以回答开放/封闭的问题:如果您打算通过设计将$codeMap 锁定并且不打算以其他方式使用它,那么您很好。但是正如我上面所说,一旦您需要更好地控制$codeMap 数组,您将需要违反原则来这样做。我的建议是集思广益,您希望在类中内置多少工厂管理,并使其成为类核心功能的一部分。
至于测试,我不明白你为什么不能按原样测试这段代码。您可以设置您的代码映射,然后测试使用create() 方法返回的相应实例。
class FactoryTest extends PHPUnit_Framework_TestCase
{
private $factory;
public function setUp()
{
$this->factory = new My_ThingFactory();
}
public function tearDown()
{
$this->factory = null;
}
public function testMadeConcreteA()
{
$this->assertInstanceOf('My_Thing_ConcreteA', $this->factory->create('A111'));
}
public function testMadeStealthBomber()
{
$this->factory->setCodeMap(array('B-52', 'StealthBomber')); //Assume the class exists.
$this->assertInstanceOf('StealthBomber', $this->factory->create('B-52'));
}
public function testDidntMakeSquat()
{
$this->assertNotInstanceOf('My_Thing_ConcreteA', $this->factory->create('Nada'));
}
}