我试图概念化为Yelp或FB签到类型系统编写代码的最清晰的方法,但是 带有退房组件。我使用的是PHP。
基本要求可能是: 报到: 如果它是类型'建立',我需要
如果是' room',我需要
退房'阶段也是如此,我提到你可以理解它并不像你说的那样真的像Yelp "我在这里"。办理登机手续并非一蹴而就;接下来是退房'我在这里不会介绍 为了简洁起见。我的问题是为结构化代码创建更清晰的控制器,方法和设计模式 满足上述要求。
因此,请求发送json,点击(Slim)应用程序,转到该方法的控制器(在本例中为Post)。我们有 他们的GPS坐标,他们正在检查的建筑物/房间的UUID,他们的ID(通过身份验证)和类型 办理登机手续,建筑物或房间。类似的东西:
{
"latitude": "33.333", // these only matter if it is 'building'
"longitude": "-80.343", // these only matter if it is 'building'
"buildingUuid": "ff97f741-dba2-415a-a9e0-5a64633e13ad", // could also be 'roomUuid' ...
"type": "building", // or 'room'
"exceptionReason": null
}
我有能力检查他们与建筑物坐标的关系,查看建筑物ID等。我是 寻找有关如何使此代码简单,可维护和可测试的想法。首先,你可以看到我的 switch语句(远程代码块)已经失控,但我不知道如何构建它。 那是 问题的关键。
没有任何要求:(操作代码)
switch($type) {
case 'building':
$model = new \Namespace\Models\Building($this->container);
break;
case 'room':
$model = new \Namespace\Models\Room($this->container);
break;
default:
throw new \InvalidArgumentException("Type {$type} not understood");
}
$model->checkIn(); // polymorphic method that all 'type' classes will have, based on an interface implemented
我试图避免使用switch语句,但在某些时候我必须使用某些东西来找出要实例化的 , 对?多态性对我没有帮助,因为我理解它对许多转换语句都有帮助,因为我还没有 有一个对象。
所以,对我来说,这似乎很简单。什么不清楚是什么时候我想添加一些要求。什么是 处理这种类型结构的正确方法(只涉及两种类型......这可能会失控 匆忙)。
(驾驶代码)
switch ($type) {
case 'building':
$model = new \Namespace\Models\CheckInBuilding($this->container);
$alreadyInTest = new \Namespace\Models\Buildings\BuildingTestIn($this->container);
$building = new \Namespace\Models\Buildings\Building($this->getData('buildingUuid'), $this->container);
if (!$building) {
throw new Exceptions\FailBadInput('Building not found: ' . $this->getData('buildingUuid'));
}
$model->setBuilding($building); // building object used for these properties: ID, coordinates for the lat/long 'nearby' check
break;
case 'room':
$model = new \Namespace\Models\CheckInRoom($this->container);
$alreadyInTest = new \Namespace\Models\Rooms\RoomTestIn($this->container);
$room = new \Namespace\Models\Rooms\Room($this->getData('roomUuid'), $this->container);
if (!$room) {
throw new Exceptions\FailBadInput('Room not found: ' . $this->getData('roomUuid'));
}
$model->setRoom($room); // room object used for these properties: ID
break;
default:
throw new \InvalidArgumentException("Type {$type} not understood");
}
$model->setAlreadyInTest($alreadyInTest);
$model->setData($this->getData());
$model->checkIn();
//
// Now, for 'building|room', this has all the data internal to check:
// - if they are nearby (but only if in building)
// - to test if they are already logged in
// - to log the primary key ID with the request
//
//
// In addition, and not covered here, if they are not in range of the building, they can still check-in, but need to
// type a short reason why they are doing a check-in and not in nearby range ('GPS broken, etc', who knows...). So,
// would I add yet another class, instantiated here so it can be mocked in a test, and passed in empty, so it could
// eventually be used to insert an exception reason (in a different table than the check-in table)?
//
根据设计模式,如果我需要添加另一个$type
,我只是在这里做,这看起来相当不错。但...
这是在一个控制器...它滥用开关声明...它似乎脆弱/脆弱,因为所有不同
实例化并传入的东西。
我有一个DIC,但我不知道它让事情更清楚。
虽然它会清除这里的代码,但我不想在实际模型中实例化任何类(比如,我不想要 创建'已经在测试者''对象内部的对象)因为我希望这是可测试的,并且这样做 会使测试/模拟变得更加困难。
话虽如此,测试也有同样的问题。这些不同的要求和如何测试有很多 他们,测试不是很孤立。我可以模拟alreadyInTest和建筑/房间对象来隔离 checkIn方法,并单独测试建筑物/房间,但要一起测试它们,就像在集成测试中一样,现在我 风险非确定性测试,因为我觉得这是一个混乱的方法。
我的最后一个想法是这样的,但我担心控制器过多增肥:(操作代码)
switch($type) {
case 'building':
$alreadyInTest = new \Namespace\Models\Buildings\BuildingTestIn($this->container);
if($alreadyInTest->isIn()) {
throw new \InvalidArgumentException('You are already checked in to a building');
}
$building = new \Namespace\Models\Buildings\Building($this->getData('buildingUuid'), $this->container);
if (!$building) {
throw new Exceptions\FailBadInput('Building not found: ' . $this->getData('buildingUuid'));
}
$model = new \Namespace\Models\Building($this->container);
break;
case 'room':
$alreadyInTest = new \Namespace\Models\Rooms\RoomTestIn($this->container);
if($alreadyInTest->isIn()) {
throw new \InvalidArgumentException('You are already checked in to a room');
}
$room = new \Namespace\Models\Rooms\Room($this->getData('roomUuid'), $this->container);
if (!$room) {
throw new Exceptions\FailBadInput('Room not found: ' . $this->getData('roomUuid'));
}
$model = new \Namespace\Models\Room($this->container);
break;
default:
throw new \InvalidArgumentException("Type {$type} not understood");
}
$model->setData($this->getData());
$model->checkIn();
同样,我觉得我应该在其他地方抽象那两个if / throws(每个案例),但这似乎并不能使这个 更简单(另外:我承认这不是一个复杂的例子......),控制器不是任何更瘦的 在两个例子中。我觉得最后一个例子对我来说更清楚了。对我而言,关键在于每次都会出现问题 补充说,这意味着在switch语句中添加更多内容。我认为多态系统会更好,但从那以后 会有外部类需要进行需求检查,我必须实例化并传递大量的内容 反正的对象,使它同样复杂。在每个签入对象中实例化类不是可测试的。一世 我认为也许责任链或命令模式可能是有用的,但似乎并不是真的适合。
我四处转转。
那么,这是最好的方式之一,还是我可以做得更好?