1

假设我有一门课来模拟一个城市。其特点如下:

  • 它只有两个属性“name”和“population”,都是在构造函数中设置的私有属性。
  • 它具有这些属性的 getter,但没有 setter。

我不希望此类的任何用户设置属性,我希望他们使用公共 .edit() 方法。

这种方法需要打开一个表格来输入城市和人口的新名称,即:一个视图。然后,如果我有一个视图,我想实现 MVC 模式,所以我的想法是控制器接收 .edit() 调用,呈现视图,检索数据,并将其发送到视图,以便它改变了它的状态。

但是,如果这样做,我必须将城市模型的属性从私有更改为公共。因此,如果任何用户实例化我的类,她/他可以直接更改属性。

所以,哲学问题:这不是打破封装吗?

编辑只是为了使它更明确:

这种city_instance.edit()方法应该是改变对象的唯一方法。

此外,我看到我的部分问题来自对模型是对象的误解(您可以在 php mvc 框架上阅读),当它实际上是一个不同的抽象时,它是一个分组业务逻辑的层(域对象 +我猜更多的东西)

4

2 回答 2

3

免责声明:我真的不明白你在哪里提出.edit()要实施的方法,所以如果你能在那里澄清一点会有所帮助。

这里要考虑的第一件事是,在您问题的项目符号列表中,您似乎暗示一个City实例的行为就像一个不可变对象:它在构造函数中获取其实例变量,并且不允许外部的任何人更改它们。但是,您稍后声明您实际上想要创建一种可视化编辑City实例的方法。这两个要求显然会造成一些紧张,因为它们是对立的。

如果您采用 MVC 方法,通过将视图与模型分离,您有两个主要选择:

  • 将您的City对象视为不可变对象,而不是在表单中的值发生更改时编辑实例,而是丢弃原始对象并创建一个新对象。
  • 提供一种改变现有City实例的方法。

City如果您实际上将 a视为不可变对象,则第一种方法可以使您的模型保持完整。对于第二个,有许多不同的方法:

  • 最标准的方法是在City类中提供一个 mutator。这可以具有每个属性的独立设置器的形状,也可以具有通用消息(我认为这是.edit()您提到的方法)的形式,以通过获取数组来一次更改许多属性。请注意,这里您没有将表单对象作为参数,因为模型不应该知道视图。如果您希望您的视图记录模型中的内部变化,您可以使用观察者模式。
  • 对控制器使用“朋友”类。一些语言允许友元类访问对象的内部。在这种情况下,您可以创建一个控制器,它是您的模型的友元类,它可以在模型和视图之间建立连接,而无需向您的模型添加修改器。
  • 使用反射来完成类似于朋友类的事情。

这三种方法中的第一种是唯一与语言无关的选择。这是否会破坏封装很难说,因为需求本身会发生冲突(这基本上意味着希望将模型与用户可以更改的视图分开,但不允许模型本身为外部改变)。但是,如果您想要可变实例,我同意将模型与视图分离可以促进具有显式突变机制。

高温高压

于 2013-03-14T20:49:38.557 回答
1

注意:我指的是 MVC,因为它适用于 Web 应用程序。MVC 可以应用于多种应用程序,并且它以多种方式实现,因此很难说 MVC 做了或不做任何特定的事情,除非你严格地谈论由模式定义的东西,而不是特定的实现.

我认为您对“封装”是什么有一个非常具体的看法,这种看法不符合教科书对封装的定义,也不符合它的常见用法。我找不到“封装”的定义,它要求没有设置器。事实上,由于 Setter 本身就是用于“编辑”对象的方法,所以这是一种愚蠢的论点。

从维基百科条目(注意它说“像 getter 和 setter”):

一般来说,封装是OOP(面向对象编程)的四大基础之一。封装就是把变量或者东西隐藏在一个类里面,防止未经授权的人使用。因此 getter 和 setter 等公共方法访问它,其他类调用这些方法进行访问。

http://en.wikipedia.org/wiki/Encapsulation_(面向对象编程)

现在,这并不是说 MVC 不会破坏封装,我只是说您对封装的概念非常具体,而不是特别规范。

当然,使用 Getter 和 Setter 可能会导致许多问题,例如返回列表,然后您可以直接在对象本身之外更改这些列表。您必须小心(如果您关心)隐藏您的数据。您还可以将一个集合替换为另一个集合,这可能不是您想要的。

得墨忒耳法则在这里比其他任何东西都更重要。

但无论如何,所有这一切实际上只是一个红鲱鱼。MVC 只讲 GUI,GUI 应该尽可能简单。它在视图或控制器中应该几乎没有逻辑。您应该使用简单的视图模型将您的表单数据反序列化为一个简单的结构,该结构可用于您喜欢的任何业务架构(如果您不想要设置器,则使用不需要的对象创建业务层使用 setter 并使用 mutattors。)。

UI 层几乎不需要复杂的架构。UI 层更像是一个边界和网关,它将 HTTP 的平面形式和命令性质转换为您选择的任何业务对象模型。因此,在 UI 级别不会是纯粹的 OO,因为 HTTP 不是。

这称为阻抗不匹配,通常与 ORM 相关联,因为对象模型不容易映射到关系模型。HTTP 到业务对象也是如此。在这方面,您可以将 MVC 视为 ORM 的必然结果。

于 2013-03-14T21:02:23.720 回答