11

Я программировал на PHP несколько лет и в прошлом использовал собственные методы обработки данных в своих приложениях.PHP Domain Model

Я создал свой собственный MVC в прошлом и имею разумное понимание ООП в PHP, но я знаю, что моя реализация требует некоторой серьезной работы.

В прошлом я использовал отношения is-a между моделью и таблицей базы данных. Теперь я знаю, после нескольких исследований, что это не лучший способ продвижения вперед. Насколько я понимаю, я должен создавать модели, которые действительно не заботятся о базовой базе данных (или о том, какой механизм хранения следует использовать), но только заботятся об их действиях и их данных.

Из этого я установил, что могу создавать модели let, например, Person . У этого объекта человека могут быть дети (человеческие дети), которые также являются объектами Person, хранящимися в массиве (с помощью методов addPerson и removePerson, принятие объекта Person).

Тогда я мог бы создать PersonMapper, который мог бы использовать для получения Лица с определенным «идентификатором» или для сохранения Лица.

Затем можно найти данные отношений в таблице поиска и создать связанные дочерние объекты для запрашиваемого лица (если они есть), а также сохранить данные в таблице поиска в команде сохранения.

Это теперь раздвигают пределы моих знаний .....

Что делать, если я хотел смоделировать здание с различными уровнями и различными помещениями в пределах этих уровней? Что, если я захочу разместить некоторые предметы в этих комнатах?

бы создать класс для строительства, уровня, комнаты и пункта

со следующей структурой.

здание может иметь 1 или несколько объектов уровня, проводимых в уровне массива может иметь 1 или много номеров объектов проводятся в массиве комнаты может иметь 1 или множество объектов, записи проводимых в массиве

и картограф для каждого класс с более высоким уровнем отображения с использованием дочерних карт для заполнения массивов (по запросу объекта верхнего уровня или ленивой загрузки по запросу)

Это, кажется, плотно соединяет разные объекты, хотя и в одном направлении (т. не нужно находиться в здании, но здание может иметь уровни)

Правильно ли это?

В представлении я хочу показать здание с возможностью выбора уровня, а затем показать уровень с возможностью выбора комнаты и т. Д., Но я также могу показать структуру, подобную дереву, в здание, на каком уровне и в каком помещении они находятся.

Надеюсь, это имеет смысл. Я просто борюсь с концепцией вложенных объектов друг в друга, когда общая концепция oop, кажется, состоит в том, чтобы разделить вещи.

Если кто-то может помочь, это было бы очень полезно.

+0

Вложение звучит правильно. вы можете попробовать задать тот же вопрос на сайте [Programmers Site] (http://programmers.stackexchange.com) – Malachi

+0

не подписывать свои сообщения, пожалуйста, – Malachi

+0

Жаль о подписании сообщений, в будущем этого делать не буду. –

ответ

0

Если я правильно понимаю ваш вопрос, ваша основная проблема заключается в том, что вы не используете абстрактные классы должным образом.В принципе, у вас должны быть разные классы для каждого вашего здания, уровней, комнат и т. Д. Например, у вас должен быть абстрактный класс Building, абстрактный класс Levels, который расширяется Building и т. Д., Зависит от того, что вы хотите иметь точно, и например, у вас есть дерево building-> level-> room, но это больше похоже на двойной список, потому что каждое здание имеет массив объектов уровня, и каждый уровень имеет родительский объект здания. Вы также должны использовать интерфейсы, так как многие люди игнорируют их, и они помогут вам и вашей команде в будущем.

Что касается моделей зданий на более общем пути, лучшим способом сделать это, на мой взгляд, является класс, который реализует те же методы для каждого типа базы данных или другого метода хранения, который вы используете. Например, у вас есть база данных mongo и база данных mysql, у вас будет класс для каждого из них, и у них будут такие методы, как добавление, удаление, обновление, push и т. Д. Чтобы быть уверенным, что вы не совершаете никаких ошибок, и все будет работайте правильно, лучший способ сделать это - иметь базу данных интерфейса, которая будет хранить методы, и вы не будете использовать метод mongo где-нибудь, где метод mysql не определен. Вы также можете определить абстрактный класс для общих методов, если они есть. Надеюсь, это будет полезно, ура!

+0

http://en.wikipedia.org/wiki/Composition_over_inheritance –

3

Это сейчас раздвигает границы, насколько мне известно .....

Здание/уровень/номер/структура товар вы описали звуки прекрасно для меня. Дизайн, основанный на домене, - это понимание вашего домена, а затем моделирование концепций как объектов. Если вы можете описать, что хотите, простыми словами, вы уже выполнили свою задачу. Когда вы разрабатываете свой домен, держите все остальное (например, постоянство) вне изображения, и будет намного проще отслеживать все.

Это, кажется, тесно пара различных объектов, хотя в одном направлении

Там нет ничего плохого в этом. Здания в реальном мире имеют полы, комнаты и т. Д., И вы просто моделируете этот факт.

и картограф для каждого класса с более высоким уровнем картографами, используя дочерние картограф

В терминологии DDD, эти «картографы» называют «хранилищами». Кроме того, ваш объект Building может считаться «совокупным», если он владеет всеми полами/комнатами/предметами внутри него, и если нет смысла загружать Room сам по себе без здания. В этом случае вам понадобится только один BuildingRepository, который может загрузить все дерево зданий. Если вы используете любую современную библиотеку ORM, она должна автоматически выполнять всю работу по составлению карт (включая загрузку дочерних объектов).

+0

Одна небольшая поправка, совокупность - это здание с полом и все такое. Само здание, по крайней мере, для некоторых контекстов, Корень Aggreagate («Основной» объект, который будет действовать как фасад для всей совокупности). Кроме того, репозитории - это немного картографов, но не в смысле ORM. Репозиторий может использовать один или несколько ORM. Btw, сущности ORM НЕ являются объектами домена, они являются объектами постоянства. – MikeSW

9

Допустим, вы упорядочивать объекты, как так: enter image description here

Для того, чтобы инициализировать весь строительный объект (с уровнями, комнаты, предметы), вы должны предоставить классы дб слоя, чтобы сделать работу. Один из способов, забирающего все, что нужно для древовидного здания:

(увеличить браузер для лучшего обзора)

zoom for better view

Здание будет проинициализировалось с в зависимости от соответствующих данных на картографах в качестве аргументов для метода initializeById.Этот подход также может работать при инициализации уровней и комнат. (Примечание: Повторное использование этих initializeById методов при инициализации всего здания приведет к большой БД запросов, поэтому я использовал немного результатов индексирования трюка и SQL IN opetator)

class RoomMapper implements RoomMapperInterface { 

    public function fetchByLevelIds(array $levelIds) { 
     foreach ($levelIds as $levelId) { 
      $indexedRooms[$levelId] = array(); 
     } 

     //SELECT FROM room WHERE level_id IN (comma separated $levelIds) 
     // ... 
     //$roomsData = fetchAll(); 

     foreach ($roomsData as $roomData) { 
      $indexedRooms[$roomData['level_id']][] = $roomData; 
     } 

     return $indexedRooms; 
    } 

} 

Теперь предположим, что мы имеем эту дб схему

enter image description here

И, наконец, некоторый код.

Строительство

class Building implements BuildingInterface { 

    /** 
    * @var int 
    */ 
    private $id; 

    /** 
    * @var string 
    */ 
    private $name; 

    /** 
    * @var LevelInterface[] 
    */ 
    private $levels = array(); 

    private function setData(array $data) { 
     $this->id = $data['id']; 
     $this->name = $data['name']; 
    } 

    public function __construct(array $data = NULL) { 
     if (NULL !== $data) { 
      $this->setData($data); 
     } 
    } 

    public function addLevel(LevelInterface $level) { 
     $this->levels[$level->getId()] = $level; 
    } 

    /** 
    * Initializes building data from the database. 
    * If all mappers are provided all data about levels, rooms and items 
    * will be initialized 
    * 
    * @param BuildingMapperInterface $buildingMapper 
    * @param LevelMapperInterface $levelMapper 
    * @param RoomMapperInterface $roomMapper 
    * @param ItemMapperInterface $itemMapper 
    */ 
    public function initializeById(BuildingMapperInterface $buildingMapper, 
      LevelMapperInterface $levelMapper = NULL, 
      RoomMapperInterface $roomMapper = NULL, 
      ItemMapperInterface $itemMapper = NULL) { 

     $buildingData = $buildingMapper->fetchById($this->id); 

     $this->setData($buildingData); 

     if (NULL !== $levelMapper) { 
      //level mapper provided, fetching bulding levels data 
      $levelsData = $levelMapper->fetchByBuildingId($this->id); 

      //indexing levels by id 
      foreach ($levelsData as $levelData) { 
       $levels[$levelData['id']] = new Level($levelData); 
      } 

      //fetching room data for each level in the building 
      if (NULL !== $roomMapper) { 
       $levelIds = array_keys($levels); 

       if (!empty($levelIds)) { 
        /** 
        * mapper will return an array level rooms 
        * indexed by levelId 
        * array($levelId => array($room1Data, $room2Data, ...)) 
        */ 
        $indexedRooms = $roomMapper->fetchByLevelIds($levelIds); 

        $rooms = array(); 

        foreach ($indexedRooms as $levelId => $levelRooms) { 
         //looping through rooms, key is level id 
         foreach ($levelRooms as $levelRoomData) { 
          $newRoom = new Room($levelRoomData); 

          //parent level easy to find 
          $levels[$levelId]->addRoom($newRoom); 

          //keeping track of all the rooms fetched 
          //for easier association if item mapper provided 
          $rooms[$newRoom->getId()] = $newRoom; 
         } 
        } 

        if (NULL !== $itemMapper) { 
         $roomIds = array_keys($rooms); 
         $indexedItems = $itemMapper->fetchByRoomIds($roomIds); 

         foreach ($indexedItems as $roomId => $roomItems) { 
          foreach ($roomItems as $roomItemData) { 
           $newItem = new Item($roomItemData); 
           $rooms[$roomId]->addItem($newItem); 
          } 
         } 
        } 
       } 
      } 

      $this->levels = $levels; 
     } 
    } 

} 

Уровень

class Level implements LevelInterface { 

    private $id; 
    private $buildingId; 
    private $number; 

    /** 
    * @var RoomInterface[] 
    */ 
    private $rooms; 

    private function setData(array $data) { 
     $this->id = $data['id']; 
     $this->buildingId = $data['building_id']; 
     $this->number = $data['number']; 
    } 

    public function __construct(array $data = NULL) { 
     if (NULL !== $data) { 
      $this->setData($data); 
     } 
    } 

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

    public function addRoom(RoomInterface $room) { 
     $this->rooms[$room->getId()] = $room; 
    } 

} 

номер

class Room implements RoomInterface { 

    private $id; 
    private $levelId; 
    private $number; 

    /** 
    * Items in this room 
    * @var ItemInterface[] 
    */ 
    private $items; 

    private function setData(array $roomData) { 
     $this->id = $roomData['id']; 
     $this->levelId = $roomData['level_id']; 
     $this->number = $roomData['number']; 
    } 

    private function getData() { 
     return array(
      'level_id' => $this->levelId, 
      'number' => $this->number 
     ); 
    } 

    public function __construct(array $data = NULL) { 
     if (NULL !== $data) { 
      $this->setData($data); 
     } 
    } 

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

    public function addItem(ItemInterface $item) { 
     $this->items[$item->getId()] = $item; 
    } 

    /** 
    * Saves room in the databse, will do an update if room has an id 
    * @param RoomMapperInterface $roomMapper 
    */ 
    public function save(RoomMapperInterface $roomMapper) { 
     if (NULL === $this->id) { 
      //insert 
      $roomMapper->insert($this->getData()); 
     } else { 
      //update 
      $where['id'] = $this->id; 
      $roomMapper->update($this->getData(), $where); 
     } 
    } 

} 

Пункт

class Item implements ItemInterface { 

    private $id; 
    private $roomId; 
    private $name; 

    private function setData(array $data) { 
     $this->id = $data['id']; 
     $this->roomId = $data['room_id']; 
     $this->name = $data['name']; 
    } 

    public function __construct(array $data = NULL) { 
     if (NULL !== $data) { 
      $this->setData($data); 
     } 
    } 

    /** 
    * Returns room id (needed for indexing) 
    * @return int 
    */ 
    public function getId() { 
     return $this->id; 
    } 

} 
Смежные вопросы