ヌルオブジェクトの導入 (リファクタリング-p260)
リファクタリング
Published: 2019-02-28

目的

「リファクタリング」を理解するためにサンプルコードを PHP で書き換えてみました。

今回は「ヌルオブジェクトの導入」について書きます。

「ヌルオブジェクトの導入」 について

null値のチェックが繰り返し現れる。

そのnull値をヌルオブジェクトで置き換える。

ポリモーフィズムの真髄は、オブジェクトのタイプを尋ねてその答えに基づいて振る舞いを呼び出すというものではなく、タイプを尋ねずにその振る舞いをただ呼ぶだけですませようというものです。

こうした振る舞いの移動は、ほとんどのクライアントが同じ応答を要求しているときにのみ意味があるということを忘れないでください。

変更前

<?php

class Site
{
    /* @var Customer */
    private $_customer;

    public function getCustomer()
    {
        return $this->_customer;
    }
}

class Customer
{
    public function getName()
    {
        // 空実装
    }

    public function getPlan()
    {
        // 空実装
    }

    public function getHistory()
    {
        // 空実装
    }
}

class PaymentHistory
{
    public function getWeeksDelingquentInLastYear()
    {
        return 7000;
    }
}

class BillingPlan
{
    private $_amount = 1000;

    private function __construct($amount)
    {
        $this->_amount = $amount;
    }

    public static function basic()
    {
        return new self(1000);
    }
}

$site = new Site();

$customer = $site->getCustomer();
if (is_null($customer)) {
    $plan = BillingPlan::basic();
} else {
    $plan = $customer->getPlan();
}

if (is_null($customer)) {
    $customerName = 'occupant';
} else {
    $customerName = $customer->getName();
}

if (is_null($customer)) {
    $weekDelinquent = 0;
} else {
    $weekDelinquent = $customer->getHistory()->getWeeksDelingquentInLastYear();
}

echo 'customerName: ' . $customerName . "\n";
echo 'weekDelinquent: ' . $weekDelinquent . "\n";

変更後

<?php

class Site2
{
    /* @var Customer */
    private $_customer;

    public function getCustomer()
    {
        return is_null($this->_customer) ?
            Customer2::newNull() :
            $this->_customer;
    }
}

class Customer2
{
    protected function __construct()
    {
    }

    public function getName()
    {
        // 空実装
    }

    public function getPlan()
    {
        // 空実装
    }

    public function getHistory()
    {
        // 空実装
    }

    public function newNull()
    {
        return new NullCustomer2();
    }
}

class NullCustomer2 extends Customer2
{
    public function getName()
    {
        return 'occupant';
    }

    public function getPlan()
    {
        return BillingPlan2::basic();
    }

    public function getHistory()
    {
        return PaymentHistory2::newNull();
    }
}

class PaymentHistory2
{
    public function getWeeksDelingquentInLastYear()
    {
        return 7000;
    }

    public static function newNull()
    {
        return new NullPaymentHistory2();
    }
}

class NullPaymentHistory2 extends PaymentHistory2
{
    public function getWeeksDelingquentInLastYear()
    {
        return 0;
    }
}

class BillingPlan2
{
    private $_amount = 1000;

    private function __construct($amount)
    {
        $this->_amount = $amount;
    }

    public static function basic()
    {
        return new self(1000);
    }
}

$site = new Site2();

$customer = $site->getCustomer();
$plan = $customer->getPlan();

$customerName = $customer->getName();

$weekDelinquent = $customer->getHistory()->getWeeksDelingquentInLastYear();

echo 'customerName: ' . $customerName . "\n";
echo 'weekDelinquent: ' . $weekDelinquent . "\n";