2

我有一个带有表示层、业务层、DAL 和业务对象层的 n 层应用程序。分离对象和写在对象上的操作打破了面向对象的封装概念。

4

4 回答 4

2

不。考虑一下“封装”的含义:类的实现细节隐藏在类的接口(消息或方法)后面。

事实上,您可以直接从 OO 原则和帕纳斯定律推导出 n 层架构:模块应该封装可能发生变化的内容。表示层封装了创建“可见”界面的细节;中间层是业务本身的模型;以及后端访问持久数据存储的详细信息。

于 2009-02-27T08:35:02.320 回答
1

举个例子,取自这篇文章

public class Position
{
  public double distance( Position position )
  {
    // calculate and return distance...
  }

  public double heading( Position position )
  {
    // calculate and return heading...
  }

  public double latitude;
  public double longitude;
}

根据同一篇文章,这是一个很好的封装示例,因为数据和对该数据执行的操作是捆绑在一起的。请注意,此处的封装不保证数据隐藏或保护。

相反,Steve McConnell 在 Code Complete(第 2 版,第 6.2 节,良好封装)中认为封装被破坏,因为成员数据被暴露。

在您的情况下,如果您的数据对象和操作它们的对象是分开的但没有公共字段,则根据第一个定义,封装被破坏,但不一定在第二种情况下。所以我们有两种截然不同的观点。一个人说数据隐藏不是封装的一部分,另一个消息来源说数据隐藏是封装的重要组成部分。

数据隐藏可以看作是信息隐藏的一部分,这是规定您应该隐藏复杂的设计决策和变更来源的原则。普遍的共识似乎是,封装被视为信息隐藏的一种表现形式,包括数据隐藏。

或者,正如维基百科所说:

封装一词通常与信息隐藏互换使用。不过,并非所有人都同意两者之间的区别。可以将信息隐藏视为原理,将封装视为技术。软件模块通过将信息封装到提供接口的模块或其他结构中来隐藏信息。

但是...本段后面的参考文献与我从第一个示例中提取的文章相同,所以即使是维基百科也在这里混淆了东西。此外,这里使用“区别”一词似乎是错误的。

最后不得不说这个有点蹩脚,但是封装和信息隐藏的术语已经超载,所以这一切都取决于来源。在您的情况下,我会坚持将封装定义为“将实现细节隐藏在抽象后面”。因此,您不一定要破坏封装。

于 2009-02-27T11:18:10.790 回答
0

这是一个非常棒的点AP!

在某些情况下,我同意将单个操作分解为多个对象确实会对封装产生不利影响。事实上,我认为这是我在许多 Web 架构中看到的一个大问题。

另一方面,某些东西对分解很有用,例如向数据库发送查询的对象等。

我认为在许多情况下,有一个论据可以更好地“封装”网页,以便更多的功能包含在单个对象或更少的对象中。因此,一种更“以页面为中心”的方法,而不是将逻辑分散到大量类中。

我认为这是我们在设计每个系统时总是要问自己的一个重要问题——要抽象多少?具体要多少?如何有效地将系统分解为类。

于 2009-02-27T06:02:51.547 回答
-1

两者不一样。架构更多地是指模块(类组)。封装是指隐藏类的内部工作。如果您的系统设计得足够好,您可以同时拥有两者。

您可能需要注意的是明确定义责任分离。只要你清楚每个模块/层的用途,并具体了解每个类的作用(以及类的每个方法的作用),那么你应该能够有一个好的设计。

我在这里只是推测,但在设计模块接口时,您可能对外观设计模式感兴趣。

关于您下面的评论,逻辑绝对应该在员工类本身中。我会质疑为业务对象设置单独层的逻辑。定义像“Employee”这样的类通常是一种诱惑,因为它们对现实世界的对象或概念进行建模。但是,您定义类的动机不应该是“为真实世界对象建模”。

你应该定义你的模块的目的(为什么你有一个业务逻辑层?包含所有的业务逻辑。)然后把你需要的东西放在那里。如果“Employee”类是需要计算业务逻辑的类,那么它应该进入业务逻辑类。如果不是,那么它应该放在您的业务对象类中(无论是什么)。如果它需要做两件不同的事情,因此可以放在两层中,那么考虑将它分成两个类 - 请记住,您的对象不需要对现实世界的事物进行建模。Robert C Martin 建议定义你的类,这样类的边界就是目的的边界。

于 2009-02-27T05:19:44.863 回答