让 setter 设置属于另一个 class 的 属性 的值

Letting a setter set a value of a property belonging to another class

setter 是否应该始终设置其直接属性的值,而不是关联对象的属性的值?例如,我有类似下面的内容,其中 API 客户端接收 XML:

Class XML {
    private $value;

    // Setter for $value exists here
    ...
}

Class Client {
    private $xml; // XML
    public function __construct(XML $xml)
    {
        $this->xml = $xml;
        ...
    }    
}

我想在实例化 Client 之后修改 $value,因为,比方说,我想更改请求或向请求添加一些选项。我应该在 XML 中使用 setter 并在修改请求时重新实例化 Client ,还是直接在 Client 中使用 setter 这样我就不会需要重新实例化Client?

我通常更喜欢前者,但为什么会更喜欢后一种方法?除了更容易进行快速更改之外,我想不出任何其他方法。

一般来说,如果 class 有 public 方法,就意味着可以访问它们。所以,使用它们没有坏处,你可能会想。

但是,问问自己:为什么 class 首先有 getters/setters?通常可以在 classes 上找到数据对象的访问器。这些对象的主要目的是携带数据,它们通常不会 任何事情——不像服务或控制器 class.

下一个问题:构造函数有什么用?构造函数用于设置对象的内部状态,它需要它的 dependencies 作为参数。本着松散耦合的精神,依赖项不应与其他 classes 可变。

查看您的代码,我猜您正在编写某种基于 XML 的客户端应用程序并且您希望 Client class 依赖于XML class.

Client 修改 XML 对象的内部状态是一个 坏主意 。依赖于该实例的其他 classes 将不知道修改并可能会得到意外结果。

有几种方法可以解决这个问题,具体取决于要执行的实际任务:

1) 如果只需要为XML的单个方法调用的上下文设置值,修改方法以$value作为参数。但是不要将其设置为XML!

中的对象成员
class XML
{
    public function doSomething($value)
    {
        …

        // do whatever you need with $value, 
        // but do *not* do something like $this->value = $value
    }
}

2) 如果与 $value 的交互需要在多个操作中保持一致,您应该将这些操作从 XML 提取到自己的工作程序或数据对象 class 中。 XML 然后应该有一个工厂方法来创建这个助手 class 的实例。然后 XMLClient 可能有使用 worker 的方法:

class XML
{
    public function createWorker($value)
    {
        return new XmlWorker($value, $this);

        // XmlWorker might even contain a reference to the XML instance, e.g.
        return new XmlWorker($value, $this);
    }

    public function doSomethingWithWorker(XmlWorker $worker)
    {
        $value = $worker->getValue();
        $worker->doWork();
    }
}

class Client
{
    private function doSomething()
    {
        $worker = $this->xml->createWorker($value);
        $worker->doWork();
    }
}

我建议阅读 设计模式;在这种情况下,尤其是关于松散耦合和关注点分离、工厂方法和依赖注入。