オブジェクトコンストラクターのオーバーロードをクリーンアップするために、ここで提供された提案や他の提案について考えてきました。私が決めた方法は、OO エレガントで、実装が簡単で、直感的に使用できると思います。
解決策として、コンストラクターの引数に共通のインターフェイスを実装することにしました。インターフェイスを作成することから始めました。
interface Geodetic_XyzFormat
{
public function getX();
public function getY();
public function getZ();
}
インターフェイスで定義されたゲッターを実装するための抽象を追加し、いくつかの子クラスに共通するセッターやその他のメソッドをいくつか追加しました。
abstract class Geodetic_ECEF_Coordinates implements Geodetic_XyzFormat
{
protected $_xCoordinate;
protected $_yCoordinate;
protected $_zCoordinate;
protected function setX($xCoordinate)
{
$this->_xCoordinate = $xCoordinate;
}
public function getX()
{
return $this->_xCoordinate;
}
protected function setY($yCoordinate)
{
$this->_yCoordinate = $yCoordinate;
}
public function getY()
{
return $this->_yCoordinate;
}
protected function setZ($zCoordinate)
{
$this->_zCoordinate = $zCoordinate;
}
public function getZ()
{
return $this->_zCoordinate;
}
protected function setCoordinates($xDistance,
$yDistance,
$zDistance,
$uom)
{
$this->setX(
($xDistance instanceof Geodetic_Distance) ? $xDistance : new Geodetic_Distance($xDistance, $uom)
);
$this->setY(
($yDistance instanceof Geodetic_Distance) ? $yDistance : new Geodetic_Distance($yDistance, $uom)
);
$this->setZ(
($zDistance instanceof Geodetic_Distance) ? $zDistance : new Geodetic_Distance($zDistance, $uom)
);
}
}
私のメイン クラス コンストラクターでは、インターフェイス定義を拡張したクラスを受け入れるようにヒントを入力します。
class Geodetic_ECEF_TestClass
{
protected $_xCoordinate;
protected $_yCoordinate;
protected $_zCoordinate;
public function __construct(Geodetic_XyzFormat $xyzCoordinates = NULL)
{
if (!is_null($xyzCoordinates)) {
$this->_xCoordinate = $xyzCoordinates->getX();
$this->_yCoordinate = $xyzCoordinates->getY();
$this->_zCoordinate = $xyzCoordinates->getZ();
return;
}
// Defaults
$this->_xCoordinate = new Geodetic_Distance();
$this->_yCoordinate = new Geodetic_Distance();
$this->_zCoordinate = new Geodetic_Distance();
}
}
最後に、コンストラクター引数のさまざまなオプションをそれぞれ処理する抽象を拡張するいくつかのクラスを作成しました。この場合、値の配列と個々の値... LatLong バリアントを後で記述しますが、同じ基本原則を使用し、同じ方法で Geodetic_ECEF_Coordinates を拡張します。
class Geodetic_ECEF_CoordinateArray extends Geodetic_ECEF_Coordinates
{
public function __construct(array $coordinates = NULL, $uom = Geodetic_Distance::METRES)
{
if (is_null($coordinates))
throw new Geodetic_Exception('An array of vector coordinates must be passed');
if (count($coordinates) == 3) {
list ($xDistance, $yDistance, $zDistance) = array_values($coordinates);
} else {
throw new Geodetic_Exception('Invalid number of vectors in array');
}
$this->setCoordinates($xDistance, $yDistance, $zDistance, $uom);
}
}
class Geodetic_ECEF_CoordinateValues extends Geodetic_ECEF_Coordinates
{
public function __construct($xDistance = NULL,
$yDistance = NULL,
$zDistance = NULL,
$uom = Geodetic_Distance::METRES)
{
$this->setCoordinates($xDistance, $yDistance, $zDistance, $uom);
}
}
そこで、ECEF オブジェクトをインスタンス化するときに、適切な Geodetic_XyzFormat オブジェクトを渡します。
// Nothing passed to constructor
$dummyECEF1 = new Geodetic_ECEF_TestClass();
var_dump($dummyECEF1);
// Array of values passed to constructor
$dummyECEF2 = new Geodetic_ECEF_TestClass(
new Geodetic_ECEF_CoordinateArray(
array(1.2, 3.4, 5.6)
)
);
var_dump($dummyECEF2);
// Individual values passed to constructor
$dummyECEF3 = new Geodetic_ECEF_TestClass(
new Geodetic_ECEF_CoordinateValues(7.8, 9.1, 2.3)
);
var_dump($dummyECEF3);
// Individual values passed to constructor (including a NULL, which should be treated as a 0)
$dummyECEF4 = new Geodetic_ECEF_TestClass(
new Geodetic_ECEF_CoordinateValues(4.5, NULL, 6.7)
);
var_dump($dummyECEF4);
$xDistance = new Geodetic_Distance(11.11, Geodetic_Distance::MILES);
$yDistance = new Geodetic_Distance(22.22, Geodetic_Distance::MILES);
$zDistance = new Geodetic_Distance(33.33, Geodetic_Distance::MILES);
// Array of distances passed to constructor
$dummyECEF5 = new Geodetic_ECEF_TestClass(
new Geodetic_ECEF_CoordinateArray(
array($xDistance, $yDistance, $zDistance)
)
);
var_dump($dummyECEF5);
$xDistance = new Geodetic_Distance(44.44, Geodetic_Distance::MILES);
$yDistance = new Geodetic_Distance(55.55, Geodetic_Distance::MILES);
$zDistance = new Geodetic_Distance(66.66, Geodetic_Distance::MILES);
// Individual distances passed to constructor
$dummyECEF6 = new Geodetic_ECEF_TestClass(
new Geodetic_ECEF_CoordinateValues($xDistance, $yDistance, $zDistance)
);
var_dump($dummyECEF6);
$xDistance = new Geodetic_Distance(11.11, Geodetic_Distance::MILES);
$yDistance = new Geodetic_Distance(22.22, Geodetic_Distance::KILOMETRES);
$zDistance = new Geodetic_Distance(33.33, Geodetic_Distance::MILES);
// Array of mixed values and distances passed to constructor
$dummyECEF7 = new Geodetic_ECEF_TestClass(
new Geodetic_ECEF_CoordinateArray(
array(11, $yDistance, 33),
Geodetic_Distance::MILES
)
);
var_dump($dummyECEF7);
$xDistance = new Geodetic_Distance(44.44, Geodetic_Distance::MILES);
$yDistance = new Geodetic_Distance(55.55, Geodetic_Distance::KILOMETRES);
$zDistance = new Geodetic_Distance(66.66, Geodetic_Distance::INCHES);
// Individual mixture of distances and values passed to constructor
$dummyECEF8 = new Geodetic_ECEF_TestClass(
new Geodetic_ECEF_CoordinateValues($xDistance, 55, $zDistance, Geodetic_Distance::NAUTICAL_MILES)
);
var_dump($dummyECEF8);
さまざまな引数の型 (ファクトリであろうと、メイン クラスであろうと) に対するすべての厄介なテストや、静的変数の使用は必要ありません (したがって、単体テストを作成するのは非常に簡単なはずです)。
提案を提供し、私に思考の糧を与えてくれたすべての人に感謝します