유효한 상태를 유지하기 위해, 즉 객체의 데이터 멤버를 업데이트하기 위해 클래스에 하나의 큰 개인 함수를 정의하는 것이 좋습니다.


18

아래 코드에서 전자 상거래 사이트의 간단한 단일 품목 구매가 사용되지만 일반적인 질문은 모든 데이터 멤버를 업데이트하여 객체의 데이터를 항상 유효한 상태로 유지하는 것입니다.

https://ko.wikibooks.org/wiki/Object_Oriented_Programming#.22State.22_is_Evil.21 과 관련하여 "일관성"및 "상태는 악"이라는 문구가 있습니다.

<?php

class CartItem {
  private $price = 0;
  private $shipping = 5; // default
  private $tax = 0;
  private $taxPC = 5; // fixed
  private $totalCost = 0;

  /* private function to update all relevant data members */
  private function updateAllDataMembers() {
    $this->tax =  $this->taxPC * 0.01 * $this->price;
    $this->totalCost = $this->price + $this->shipping + $this->tax;
  }

  public function setPrice($price) {
      $this->price = $price;
      $this->updateAllDataMembers(); /* data is now in valid state */
  }

  public function setShipping($shipping) {
    $this->shipping = $shipping;
    $this->updateAllDataMembers(); /* call this in every setter */
  }

  public function getPrice() {
    return $this->price;
  }
  public function getTaxAmt() {
    return $this->tax;
  }
  public function getShipping() {
    return $this->shipping;
  }
  public function getTotalCost() {
    return $this->totalCost;
  }
}
$i = new CartItem();
$i->setPrice(100);
$i->setShipping(20);
echo "Price = ".$i->getPrice(). 
  "<br>Shipping = ".$i->getShipping().
  "<br>Tax = ".$i->getTaxAmt().
  "<br>Total Cost = ".$i->getTotalCost();

단점이 있거나 더 좋은 방법은 무엇입니까?

관계형 데이터베이스가 지원하는 실제 응용 프로그램에서 반복되는 문제이며, 저장 프로 시저를 광범위하게 사용하지 않으면 모든 유효성 검사를 데이터베이스로 푸시합니다. 코드는 모든 런타임 상태 유지 작업을 수행해야하지만 데이터 저장소는 데이터를 저장해야한다고 생각합니다.

편집 : 이것은 관련 질문이지만 유효한 상태를 유지하기위한 하나의 큰 기능에 관한 모범 사례 권장 사항이 없습니다 : /programming/1122346/c-sharp-object-oriented-design-maintaining- 유효한 객체 상태

EDIT2 : @ eignesheep의 대답은 최선이 대답이지만 - /software//a/148109/208591이 -에서 @ eigensheep의 대답하고 내가 무엇을 알고 싶어 사이의 라인을 채우는 것입니다 - 코드해야에만 프로세스가, 전역 상태는 개체 간 DI 가능 상태 전달로 대체되어야합니다.


백분율 변수를 사용하지 않습니다. 사용자로부터 백분율을 수락하거나 사용자에게 1을 표시 할 수 있지만 프로그램 변수가 비율이면 수명이 훨씬 좋습니다.
케빈 클라인

답변:


29

다른 모든 것이 같으면 불변량을 코드로 표현해야합니다. 이 경우에는 불변이 있습니다.

$this->tax =  $this->taxPC * 0.01 * $this->price;

코드에서 이것을 표현하려면 세금 멤버 변수를 제거하고 getTaxAmt ()를

public function getTaxAmt() {
  return $this->taxPC * 0.01 * $this->price;
}

총 비용 멤버 변수를 제거하려면 비슷한 작업을 수행해야합니다.

코드에서 불변을 표현하면 버그를 피하는 데 도움이 될 수 있습니다. 원래 코드에서 setPrice 또는 setShipping을 호출하기 전에 확인하면 총 비용이 올바르지 않습니다.


3
많은 언어에 게터가 있어 그러한 함수가 속성 인 것처럼 가장 할 수 있습니다. 둘 다 최고!
curiousdannii

요점이지만, 일반적인 사용 사례는 코드가 관계형 데이터베이스 (MySQL 대부분)의 여러 테이블에있는 여러 열의 데이터를 가져 와서 저장하고 저장 프로 시저 (설명 가능하고 다른 주제 자체)를 사용하고 싶지 않은 경우입니다. : 모든 계산은 "체인"해야 함을 더이 수단 당신의 불변 인 코드 아이디어를 복용 getTotalCost()전화 getTaxAmt()등등. 즉 , 계산되지 않은 것만 저장 합니다. 우리는 함수형 프로그래밍으로 조금 움직이고 있습니까? 또한 빠른 액세스를 위해 계산 된 엔터티를 테이블에 저장하는 것이 복잡합니다. 실험이 필요합니다!
site80443

13

어떤 단점이 있습니까?

확실한. 이 방법은 항상 무언가를하는 것을 기억 하는 모든 사람에게 의존 합니다. 모든 사람과 항상 의존하는 모든 방법은 때때로 실패 할 수밖에 없습니다 .

아마도 더 좋은 방법일까요?

의식을 기억하는 부담을 피하는 한 가지 방법은 @eigensheep이 제안한 것처럼 필요에 따라 다른 속성에 의존하는 객체의 속성을 계산하는 것입니다.

다른 하나는 장바구니 항목을 변경할 수 없게 만들고 생성자 / 공장 메소드에서 계산하는 것입니다. 개체를 변경할 수없는 경우에도 일반적으로 "필요에 따라 계산"방법을 사용합니다. 그러나 계산에 너무 많은 시간이 걸리고 여러 번 읽히는 경우; "생성 중 계산"옵션을 선택할 수 있습니다.

$i = new CartItem();
$i->setPrice(100);
$i->setShipping(20);

스스로에게 물어봐야합니다. 가격이없는 장바구니 항목이 의미가 있습니까? 품목 가격이 변경 될 수 있습니까? 생성 된 후? 세금 계산 후? 등 아마도 CartItem생성자에서 불변의 가격과 배송비를 만들어야 합니다.

$i = new CartItem(100, 20);

장바구니 항목이 속한 장바구니없이 의미가 있습니까?

그렇지 않다면 $cart->addItem(100, 20)대신 기대 합니다.


3
가장 큰 단점은 작업 수행을 기억하는 사람들에게 의존하는 것이 좋은 해결책이 아니라는 것입니다. 당신이 인간에게 의지 할 수있는 유일한 것은 그들이 무언가를하는 것을 잊어 버린다는 것입니다.
corsiKa

@corsiKlause 호 호 호와 abuzittin, 고체 점은, 그와 함께 주장 할 수없는 - 사람들은 잊지 변함 . 그러나 위에서 작성한 코드는 예일 뿐이며 일부 데이터 멤버가 나중에 업데이트되는 실질적인 사용 사례가 있습니다. 내가 보는 다른 방법은 추가로 정규화하는 것입니다-독립적으로 업데이트 된 데이터 멤버가 다른 클래스에 있도록 클래스를 만들고 일부 인터페이스에 업데이트 책임을 부여하여 다른 프로그래머 (및 시간이 지난 후에 자신)가 메소드를 작성해야합니다. 컴파일러는 작성해야 함을 상기시킵니다. 그러나 그것은 더 많은 수업을 추가 할 것입니다 ...
site80443

1
@ site80443 내가 본 것에 따르면, 그것은 잘못된 접근법입니다. 자체 검증 된 데이터 만 포함되도록 데이터를 모델링하십시오. 예를 들어 품목의 가격은 음수 일 수 없으며 그 자체에만 의존 할 수 있습니다. 품목이 할인 된 경우 할인을 가격에 포함시키지 말고 나중에 할인으로 장식하십시오. 품목에 대해 $ 4.99와 20 % 할인을 별도의 실체로, 5 %의 세금을 또 다른 실체로 저장하십시오. 실제로 예제가 실제 코드를 나타내는 경우 Decorator 패턴을 고려해야하는 것처럼 보입니다.
corsiKa
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.