Whip Monstrous Code Into Shape - 06 God Object Cleanup #3: Value Objects
Extracting value objects, when appropriate, can be a useful technique for cleaning up messy classes. Use a simple metric: if you find multiple pieces of behavior that surround a single primitive or value, consider a value object. Please note that developers often have a tendency to "value object all the things," so be careful. Refactor toward value objects, rather than adopting them by default for every possible value.
这个视频讲的是如何使用 Value Object. 从名称来看就可以了解, Value Object 就是把对象的某个属性抽象成一个类。什么情况下能用到呢?一个很简单的场景,比如有个 Performance 模型,这个模型有个 revenue (收入) 属性,我们在存储比如价格、费用的情况下都习惯用“分”来做单位,但是在前端显示的时候一般用 “元”,甚至还要加上货币名称。
通常的做法就是在模型里面加上不同的方法,比如把货币转换成元,加上货币名称,甚至转换成美金等等。
class Performance extends Model
{
public function revenue()
{
return $this->revenue;
}
public function revenueInYuan()
{
return $this->revenue / 100;
}
public function revenueAsCurrency()
{
return money_format('¥%i', $this->revenueInYuan());
}
public function revenueInUsd()
{
return $this->revenueInYuan() / 6.9;
}
}
当我们看到模型里面有关于某个属性很多不同的方法的时候,这个时候可能就要考虑把属性抽象成一个 Value Object,把这些不同的表现放到这个 Value Object 中。
class Revenue
{
private $revenue;
public function __construct($revenue)
{
$this->revenue = $revenue;
}
public function revenue()
{
return $this->revenue;
}
public function inYuan()
{
return $this->revenue / 100;
}
public function asCurrency()
{
return money_format('¥%i', $this->revenueInYuan());
}
public function revenueInUsd()
{
return $this->InYuan() / 6.9;
}
}
我们已经创建了一个 Value Object,但是在用的时候每次都要实例化一个类,很麻烦的,有没有什么办法可以跟访问模型的属性一样?有,你可以在模型中添加一个 getter(访问器)。
class Performance extends Model
{
public function getRevenueAttribute($revenue)
{
return new Revenue($revenue);
}
}
这个时候你通过 $performance->revenue 返回的就是一个 Revenue 实例了,你可以通过调用不同的方法获取不同的结果:$performance->revenue->asCurrency()
就可以获取带有货币符号的值了。
更进一步的,你可以在 Revenue 中添加一个 __get 魔术方法,像访问 Revenue 属性一样获取结果。
public function __get($attribute)
{
if (method_exists($this, $attribute)) {
return $this->{$attribute}();
}
return $this->revenue;
}
你还可以给 Revenue 添加一个 __toString() 魔术方法,这样就可以在某些情况下把 Revenue 当作字符串访问了: echo $performance->revenue
.
public function __toString()
{
return (string) $this->revenue;
}
推荐文章: