我在PHP编程了好几年,在过去通过我自己的方法,我的应用程序中处理数据。
我建立我自己的MVC过去,并有PHP内OOP有一定的了解,但我知道我的实现需要一些严肃的工作。
在过去,我已经使用的是-A模型和数据库表之间的关系。 我现在才知道做一些研究,这是不是真的取得进展的最佳方式了。 据我了解,我应该创建一个并不真正关心底层数据库模型(或任何存储机制被使用),但只关心他们的行动和他们的数据。
从这个我已经确定,我可以创建模型可以说,例如一个人的这个人的对象可能有一些儿童(人类小孩)这也是一个数组举行Person对象(与addPerson的和removePerson方法,接受一个Person对象) 。
然后,我可以创造我可以用它来得到一个人与一个特定的“身份证”,或保存一个人PersonMapper。
那么这可能查找的关系数据的查找表,并创建已请求人相关的子对象(如果有的话),并同样在查找表节省save命令的数据。
这是现在推限制我的知识.....
如果我想与这些级别中的不同层次和不同的房间建筑模型? 如果我想放在这些房间的一些项目?
我会给建设,水平,房间和物品类
具有以下结构。
建筑物可具有以阵列水平保持1个或许多级对象可以具有以阵列室保持1个或许多室对象可以有以阵列保持1个或许多项目对象
和用于与使用子映射器来填充阵列更高级别映射器每个类映射器(无论是在顶层对象或请求延迟加载的请求)
这似乎紧密地结合不同的对象虽然是在一个方向(即地板并不需要在一个建筑,但建筑能有水平)
这是去了解事情的正确方法?
在视图里,我想表现出建筑的选项来选择一个级别,然后显示水平的选项来选择一个房间等等。但我也可能想表明,像在建筑项目的结构,什么树水平和房间他们英寸
我希望这是有道理的。 我只是在彼此嵌套对象的概念挣扎时,OOP的基本概念似乎是不同的东西。
如果有人能够帮助这将是非常有用的。
比方说,你组织你的对象,像这样:
为了初始化整个建筑物体(与水平,房间,物品),你必须提供DB层的类来完成这项工作。 获取你需要的建筑树视图是一切的一种方式:
( 缩放,以更好的视野浏览器 )
大厦将根据作为参数传递给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;
}
}
现在让我们说我们有这个DB模式
最后一些代码。
建造
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;
}
}
这是现在推限制我的知识.....
建筑/层/间/项目结构,你描述的效果不错给我。 领域驱动设计是所有关于了解你的域,然后建模概念对象 - 如果你能描述你想要的东西简单的话,你已经完成你的任务。 当您在设计领域,保持一切(如持久性)出来的图片,它会变得更加简单明了的事情。
这似乎紧密地结合不同的对象虽然是在一个方向
没有什么错了。 在现实世界中的建筑确实有楼层,房间等,以及你只是模拟了这一事实。
并利用孩子映射器与更高级别映射器每个类映射器
在DDD术语,这些“映射器”被称为“库”。 此外,您的Building
对象可能被认为是一个“聚合”,如果它拥有所有的楼层/间/内它的项目,如果它没有意义加载Room
本身没有建设。 在这种情况下,你只需要一个BuildingRepository
可以加载整个建筑树。 如果你使用任何现代ORM库,它会自动为你做所有的绘图工作(包括加载子对象)。
如果我理解你的问题的权利,你的主要问题是,你不使用抽象类正常。 基本上你应该有不同的类别为您的每一个建筑,水平,客房等。例如,你应该有一个抽象类建筑,由建筑扩展性等抽象类水平,取决于你想拥有什么,并且就像你有一棵树building-> LEVEL->的房间,但它更像是一个双链表,因为每个建筑都有级别对象的数组,每个级别都有一个父建筑物对象。 您还应该使用接口,很多人忽略了他们,他们会帮助你和你的团队在未来很多。
对于一个更通用的方法建立模型做在我看来,最好的办法是有一个实现每种类型的数据库,或者使用其他存储方法的相同方法的类。 例如你有一个蒙戈数据库和MySQL数据库,你将有一个类为每个这些的时候,就会有像添加,删除,更新,推送等要确保你不做任何错误,一切都会方法正常工作,做到这一点,最好的办法是有将存储方法的接口数据库,并使用一个蒙戈方法的地方在那里没有定义MySQL的方法,你就不会结束。 您也可以定义一个抽象类的常用方法,如果他们有任何。 希望这会有所帮助,干杯!