TLDR:如何将富域模型与“重型”设置器与简单的 HTML 表单映射相结合?
当一个属性的设置器更改其他属性(直接或通过使用设置器 - 这无关紧要)时,就会出现问题。
用于更好解释的示例类(在 PHP 中,但这并不重要 - 我认为):
class Product {
private $name;
private $cost;
private $profit;
private $price;
public function getName() {
return $this->name;
}
public function getCost() {
return $this->cost;
}
public function getProfit() {
return $this->profit;
}
public function getPrice() {
return $this->price;
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function setCost($cost) {
if ($this->cost !== $cost) {
$this->cost = $cost;
$this->setPrice($this->getCost() + $this->getProfit());
}
return $this;
}
public function setProfit($profit) {
if ($this->profit !== $profit) {
$this->profit = $profit;
$this->setPrice($this->getCost() + $this->getProfit());
}
return $this;
}
public function setPrice($price) {
if ($this->price !== $price) {
$this->price = $price;
$this->setProfit($this->getPrice() - $this->getCost());
}
return $this;
}
}
这个示例的想法是:您可以设置成本(购买/创造产品)和您想要赚取的利润 - 然后计算价格(销售产品)。此外,您可以设置更改价格 - 然后计算利润。(改变成本可能会触发改变利润而不是价格,但这对问题无关紧要)。
例如:
$foo = new Product();
$foo->setName("Foo");
$foo->setCost(100);
$foo->setPrice(110);
assert($foo->getProfit() == 10);
$foo->setProfit(30);
assert($foo->getPrice() == 130);
由于许多原因(即命令行前端和 CRON 作业),我需要在“后端”代码中拥有丰富的对象。
在 HTML 前端中,您会获得包含 3 个输入的表单,这些输入对应于成本、利润和价格。当用户更改值并提交设置器的表单顺序时,确实很重要并且可能会搞砸。例如:
- 用户去点击编辑产品按钮
- 看到具有值的形式:成本=100,利润=10,价格=110
- 将利润更改为 20
- 提交表格
问题是:后端映射器从 POST 表单获取值并调用: setCost(100), setProfit(20) 然后 setPrice(110) 这很糟糕,因为它是旧价格,应该更改为 120(用户想要 20利润和 100 成本)。
我看到的唯一解决方案是在前端(在 JavaScript 中)也实现所有域模型逻辑,因此更改成本/利润输入会触发更改价格输入的值。然后所有输入都具有正确的值,并且可以放置已发布的数据而不会出现“覆盖”问题。使用此示例很容易,但当您有许多字段(用两种不同的语言编写相同的代码既耗时且容易出错)或它们之间的逻辑非常复杂(并非所有内容都可以在 JS 中轻松实现)时,这是不可能的。
任何想法如何解决这个问题?:)
PS:使用瞬态属性和惰性评估(即只有成本和价格是属性和可编辑的,并且总是计算利润)不是一种选择。我必须能够从这两种方式进行改变。对于一些繁重的计算也很不方便——所有的道具都必须存在,然后保存到数据库中。