2014-12-29 3 views
1

예제로 Kent Beck의 테스트 중심 개발을 계속하고 PHP로 예제를 다시 작성하십시오.PHP 오브젝트 유형 비교 이해

13 장에서는 2 개의 객체가 같은 유형 인 경우 true를 반환하는 테스트에 대해 설명합니다. 이전 장에서는 평가가 작동하지만이 예제에서는 통과 할 수 없으며 왜 실패하는지 잘 모르겠습니다.

class Sum implements Expression { 
    public $augend; 
    public $addend; 


    public function __construct($augend, $addend) 
    { 

     $this->augend = $augend; 
     $this->addend = $addend; 

    } 

    // impl of Expression interface, but this smells to me, dupe implementation 
    // also in Money 
    public function plus($addend) { 
     return new Sum($this, $addend); 
    } 

    public function reduce($to) {   
     $amount = $this->augend->amount + $this->addend->amount; 

     return new Money($amount, $to); 
    } 
} 

표현 :

interface Expression { 
    public function plus($addend); 

    public function reduce($to); 

} 

내가 (감소라고 함) 은행 객체의 메소드를 호출하기 위해 노력하고있어 익스프레션 인터페이스를 구현하는 클래스 "합"을 감안할 때

첫 번째 인수는 자신의 reduce 구현이있는 Sum 객체입니다. 그러나, 자바 예 인터페이스로 첫 번째 인수를 지정하지 구체적인 클래스 :

class Bank { 

    // the book defines the $source param as type Expression, which is legal 
    // in Java but not in PHP 
    public function reduce($source, $to) { 

     return $source->reduce($to); 
    } 
} 

그리고 마지막으로, 내 돈 클래스 :

class Money implements Expression { 
    public $amount; 
    public $currency; 

    public function __construct($amount, $currency) { 
     $this->amount = $amount; 
     $this->currency = $currency; 
    } 

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

    public function equals($compareObject) { 

     return $this->amount == $compareObject->amount 
     && $this->currency() == $compareObject->currency(); 
    } 

    // static factory method that returns Dollar 
    // (reduces dependence on subclasses) 
    static function dollar($amount) { 
     return new Dollar($amount, "USD"); 
    } 

    static function franc($amount) { 
     return new Franc($amount, "CHF"); 
    } 

    public function times($multiplier) { 
     return new Money($this->amount * $multiplier, $this->currency); 
    } 


    // impl of Expression interface 
    public function plus($addend) { 
     return new Sum($this, $addend); 
    } 

    public function reduce($to) { 
     return $this; 
    } 
} 

이 테스트를 실행하는 경우 :

$sum = new Sum(Money::dollar(3), Money::dollar(4)); 
$bank = new Bank(); 

$result = $bank->reduce($sum, "USD"); 

$this->assertEquals(Money::dollar(7), $result); //FAIL 

각 개체의 속성이 일치하는지 확인했지만 $ result는 Money 유형이고 Dollar는 입력하지 않는다는 어설 션이 실패합니다.

$this->assertEquals(Money::dollar(7)->amount, $result->amount); 


$this->assertEquals(Money::dollar(7)->currency, $result->currency); 

본질적으로 개체를 특정 형식으로 캐스팅하는 기능이 부족하여이 효과가 있습니까? 서브 클래스의 구현을 변경하지 않았으므로 이전 테스트는 여전히 통과됩니다.

$five = Money::dollar(5); 
$this->assertEquals(new Money(10, "USD"), $five->times(2)); 
$this->assertEquals(new Money(15, "USD"), $five->times(3)); 
$this->assertEquals(get_class($five), "Dollar"); 

답변

0

두 개의 다른 유형의 객체는 절대로 같을 수 없습니다. PHP는 객체가 다른 객체와 동일하면 객체가 스스로를 결정하도록하지 않습니다. java는 equal 메소드를 사용합니다. 테스트의 경우

http://php.net/manual/en/language.oop5.object-comparison.php

당신은 eqauls 메소드를 직접 호출 할 수 있습니다.

$this->assertsTrue($result->equals(Money::dollar(7))); 
+0

나는 $ this-> assertTrue (Money :: dollar (7) -> equals ($ result));를 사용하여 결과를 얻었지만 사실은 평가되지만 깨지기 쉽다. 왜냐하면 나는 일부 고유 한 PHP 메소드 (어쨌든 존재하지 않는 것 같습니다)보다는 객체 평등의 자체 구현 –

0

이것은 phpunit 사용 문제보다 아키텍처 문제입니다. 나는 당신에게 2 가지 간단한 해결책을 주었지만, 확실히 어떤 디자인 패턴으로 코드를 향상시켜야합니다.

1

생성자에 "USD"을 통과해야하는 경우 클래스 Dollar를 정의하는 점은 무엇입니까? 대신 Money 클래스를 사용하십시오.

2

// static factory method that returns Dollar 
// (reduces dependence on subclasses) 
static function dollar($amount) { 
    return new Money($amount, "USD"); 
} 

static function franc($amount) { 
    return new Money($amount, "CHF"); 
} 

public function times($multiplier) { 
    return new Money($this->amount * $multiplier, $this->currency); 
} 

하지 아마도 다른 통화로 Dollar 돌려 Money의 합계가 (당신이 변환기구가없는 경우) 논리입니다.이 같은 Sum의 방법 reduce을 변경할 수 있습니다 예상대로 테스트가 작동이 솔루션

public function reduce() {   
    $money = clone $this->augend; 
    $money->amount = $this->augend->amount + $this->addend->amount; 

    return $money; 
} 

---

:

$sum = new Sum(Money::dollar(3), Money::dollar(4)); 
$bank = new Bank(); 

$result = $bank->reduce($sum, "USD"); 

$this->assertEquals(Money::dollar(7), $result); // OK 

이 주장이 클래스를 확인하기 때문에 객체의 평등성과 속성의 평등성.

+0

유효한 포인트가있을 때 이것이 책에서 끝나지 않을 것이라고 나는 추측 할 수 없습니다. 전반적으로 약 2/3 정도이며 Beck은 전반적으로 중요한 리팩토링을 수행합니다. –