Adding Data to an Object - Validate *then* add, or validate as you add?
Take the following example,
class Cup {}
class MyObject {
protected $cups = array();
public function addCup(Cup $cup) {
if (!in_array($cup, $this->getCups())) {
array_push($this->cups, $cup);
}
return $this;
}
public function addCups(array $cups) {
// Add cups logic, see below
}
public function getCups() {
return $this->cups;
开发者_如何学C }
public function setCups(array $cups) {
// Set cups logic, see below
}
}
On this class we can add a Cup
using $myObject->addCup()
, but we can also add multiple cups using $myObject->addCups()
, or override any existing cups with $myObject->setCups()
.
My question is, in the addCups()
and setCups()
methods, do you validate all the passed data is valid before adding them, or do you validate as you add them?
Scenario 1, validate before you add:
public function addCups(array $cups) {
foreach($cups as $cup) {
if (!($cup instanceof Cup)) {
throw new InvalidArgumentException();
}
}
foreach($cups as $cup) {
$this->addCup($cup);
}
}
Scenario 2, validate as you add:
public function addCups(array $cups) {
foreach($cups as $cup) {
if (!($cup instanceof Cup)) {
throw new InvalidArgumentException();
}
$this->addCup($cup);
}
}
I appreciate there isn't much difference in the code, but it fundamentally changes how the object adds/sets data. In scenario 1, you can only add new data to the object if all the data you are adding is valid, where as in scenario 2 data will actually be added up to the point of the error.
I personally have been using scenario 1, but I can't help but feel you might as well use scenario 2 because if you've thrown an exception, you shouldn't really be carrying on with the execution anyway?
I'd love to know if there's a concrete design pattern to follow on this, or if not people's opinions.
Thanks.
Check all items first.
This allows for transactional behavior, which is generally a Good Thing. This ensures the behavior is easy to understand and debug.
Performance wise, it is also preferable.
However, if your goal is to "do as much work as possible", then check each item and add it if possible - if one item fails, just skip over to the next. This is a rare use case, though.
I would say it depends on wether or not you want to treat adding of 'Cups' as a transaction or not. Do you want adding of all the Cups to fail when one or several Cup(s) fails, use method 1. Otherwise, method 2.
As far as I know, both methods are viable and have their own use-cases.
精彩评论