일반적으로 말하자면 Demeter의 법칙은 변경 사항을 축소 된 범위에서 유지하는 데 도움이되므로 새로운 요구 사항이나 버그 수정이 시스템 전체로 확산되지 않습니다. 이 방향에서 도움이되는 다른 디자인 가이드 라인이 있습니다 (예 : this article에 나열된 것들. 그렇게 말하면서 Demeter의 법칙 (디자인 패턴과 기타 유사한 것들)은 유용하다고 생각되는 디자인 가이드 라인으로 간주하며, 그렇게한다고 판단되면 깨뜨릴 수 있습니다. 예를 들어 나는 주로 test private methods을 사용하지 않습니다. 주로 fragile tests을 생성하기 때문입니다. 그러나 아주 특별한 경우에는 객체의 구현이 변경되면 특정 테스트가 변경 될 수 있음을 알고 있기 때문에 객체 민간 메소드를 테스트했습니다. 이는 앱에서 매우 중요하다고 생각했기 때문입니다. 물론 이러한 경우에는 신중해야하며 다른 개발자가 왜 그렇게하는지 설명하는 문서를 남겨 두어야합니다. 그러나, 결국, 당신은 좋은 판단 :)을 사용해야합니다.
이제 원래 질문으로 돌아갑니다. 지금까지 내가 쓴 문제점은 메시지 체인을 통해 액세스 할 수있는 객체 그래프의 루트 인 객체에 대한 GUI를 작성하는 것입니다. 이 경우에는 모델의 각 객체에 대한보기 구성 요소를 할당하여 모델을 만든 것과 비슷한 방식으로 GUI를 모듈화합니다. 결과적으로 해당 모델에 대해 HTML을 만드는 방법을 알고있는 OrderView
, AddressView
등과 같은 클래스를 갖게됩니다. 그런 다음 해당보기를 작성하여 최종 레이아웃을 만들 수 있습니다 (예 : OrderView
은 AddressView
을 생성 함). 또는 Mediator을 작성하여 모델에 연결하여 최종 레이아웃을 만들 수 있습니다.다음 뷰를
class ShoppingBasket
{
protected $orders;
protected $id;
public function getOrders(){...}
public function getId(){...}
}
class Order
{
protected $user;
public function getUser(){...}
}
class User
{
protected $address;
public function getAddress(){...}
}
과 : 첫 번째 방법의 예를 들어이 같은 것을 가질 수있다 (필자는, 예를 들면 PHP를 사용하는 것을, 나는 당신이 사용하는 언어를 모르는)
class ShoppingBasketView
{
protected $basket;
protected $orderViews;
public function __construct($basket)
{
$this->basket = $basket;
$this->orederViews = array();
foreach ($basket->getOrders() as $order)
{
$this->orederViews[] = new OrderView($order);
}
}
public function render()
{
$contents = $this->renderBasketDetails();
$contents .= $this->renderOrders();
return $contents;
}
protected function renderBasketDetails()
{
//Return the HTML representing the basket details
return '<H1>Shopping basket (id=' . $this->basket->getId() .')</H1>';
}
protected function renderOrders()
{
$contents = '<div id="orders">';
foreach ($this->orderViews as $orderView)
{
$contents .= orderViews->render();
}
$contents .= '</div>';
return $contents;
}
}
class OrderView
{
//The same basic pattern; store your domain model object
//and create the related sub-views
public function render()
{
$contents = $this->renderOrderDetails();
$contents .= $this->renderSubViews();
return $contents;
}
protected function renderOrderDetails()
{
//Return the HTML representing the order details
}
protected function renderOrders()
{
//Return the HTML representing the subviews by
//forwarding the render() message
}
}
하고 view.php에서 당신은 같은 것을 할 것 :이 방법은 뷰가 작성 가능 구성 요소로 취급되는 구성 요소 모델을 기반으로
$basket = //Get the basket based on the session credentials
$view = new ShoppingBasketView($basket);
echo $view->render();
합니다. 이 스키마에서는 객체의 경계를 존중하며 각 뷰에는 단일 책임이 있습니다. (영업 의견에 따라 추가)
편집
난 당신이 바구니 ID, 주문 날짜 및 사용자 이름을 렌더링 할 필요가 파단에와 있다는 견해를 정리하는 방법이 없다고 가정합니다 한 줄. 코멘트에서 말했듯이,이 경우에 대해 "잘 못된"액세스가 잘 문서화 된 단일 장소에서 수행되어이를 인식하지 못하게합니다.
class MixedView
{
protected $basketId;
protected $orderDate;
protected $userName;
public function __construct($basketId, $orderDate, $userName)
{
//Set internal state
}
public function render()
{
return '<H2>' . $this->userName . "'s basket (" . $this->basketId . ")<H2> " .
'<p>Last order placed on: ' . $this->orderDate. '</p>';
}
}
class ViewBuilder
{
protected $basket;
public function __construct($basket)
{
$this->basket = $basket;
}
public function getView()
{
$basketId = $this->basket->getID();
$orderDate = $this->basket->getLastOrder()->getDate();
$userName = $this->basket->getUser()->getName();
return new MixedView($basketId, $orderDate, $userName);
}
}
나중에에 도메인 모델을 재 배열하고 ShoppingBasket
클래스가 더 이상 getUser()
메시지를 구현할 수 없습니다 다음, 응용 프로그램에서 하나의 지점을 변경하는 모든 시스템에 걸쳐 그 변화를 피하기 위해이됩니다. 일부 속성에 액세스하는 데 사용되는 체인 경우
HTH는
무엇이 당신 질문입니까? – hakre
나는 여기에 특정한 질문이 없다는 것을 안다. 나는 현상금을 놓을 수 있었고 그 주제는 논의 할 가치가 있었기 때문에 현상금을 배치했다. 아마도 OP가 약간의 질문을 명확히 할 수 있을까요? – rdlowrey
@Tom 문제는 클래스 User, class Info 및 Order 클래스에 Product 클래스의 배열을 삽입하는 것을 좋아하지 않는다는 것입니다. 그들은 다소 독립적이다 그래도 –