首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >不同逻辑层上的接口

不同逻辑层上的接口
EN

Stack Overflow用户
提问于 2008-08-12 21:06:39
回答 9查看 4.8K关注 0票数 12

假设您的应用程序分为三层: GUI、业务逻辑和数据访问。在您的业务逻辑层中,您已经描述了您的业务对象:getter、setters、accessors等等……你明白了吧。业务逻辑层的接口保证了业务逻辑的安全使用,因此您调用的所有方法和访问器都将验证输入。

当您第一次编写UI代码时,这很棒,因为您拥有一个可以信任的定义整洁的接口。

但这里出现了棘手的部分,当您开始编写数据访问层时,业务逻辑的接口不能满足您的需求。您需要使用更多的访问器和getter来设置隐藏的字段。现在,您被迫侵蚀业务逻辑的接口;现在可以从UI层设置字段,而UI层没有业务设置。

由于数据访问层所需的更改,业务逻辑的接口已经被侵蚀到甚至可以使用无效数据设置业务逻辑的程度。因此,该接口不再保证安全使用。

我希望我已经把问题解释得足够清楚了。如何防止接口侵蚀,维护信息隐藏和封装,同时仍然适应不同层之间的不同接口需求?

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2008-08-13 06:08:25

如果我没理解错的话,您已经创建了一个域模型,并且希望编写一个对象关系映射器来在数据库中的记录和域对象之间进行映射。但是,您担心读写对象字段所需的“管道”代码会污染您的域模型。

退一步说,对于将数据映射代码放在哪里,您基本上有两个选择-在域类本身内或在外部映射类中。第一种选择通常称为活动记录模式,它的优点是每个对象都知道如何持久化自己,并且对其内部结构有足够的访问权限,以便在不需要公开与业务无关的字段的情况下执行映射。

E.g

代码语言:javascript
运行
复制
public class User
{
    private string name;
    private AccountStatus status;

    private User()
    {
    }

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public AccountStatus Status
    {
        get { return status; }
    }

    public void Activate()
    {
        status = AccountStatus.Active;
    }

    public void Suspend()
    {
        status = AccountStatus.Suspended;
    }

    public static User GetById(int id)
    {
        User fetchedUser = new User();

        // Lots of database and error-checking code
        // omitted for clarity
        // ...

        fetchedUser.name = (string) reader["Name"];
        fetchedUser.status = (int)reader["statusCode"] == 0 ? AccountStatus.Suspended : AccountStatus.Active;

        return fetchedUser;
    }

    public static void Save(User user)
    {
        // Code to save User's internal structure to database
        // ...
    }
}

在本例中,我们有一个对象,它表示一个具有名称和AccountStatus的用户。我们不想允许直接设置状态,可能是因为我们想检查更改是不是有效的状态转换,所以我们没有setter。幸运的是,GetById和Save静态方法中的映射代码可以完全访问对象的name和status字段。

第二种选择是让第二个类负责映射。这具有分离业务逻辑和持久性的不同关注点的优势,这可以使您的设计更具可测试性和灵活性。此方法的挑战在于如何将name和status字段公开给外部类。一些选择是: 1.使用反射(这对于深入挖掘对象的私有部分毫无顾虑) 2.提供特殊命名的公共setter(例如,在它们前面加上单词“private”),希望没有人意外地使用它们3.如果您的语言支持,则将setter设置为内部的,但授予您的数据映射器模块访问权限。例如,在.NET 2.0及更高版本中使用InternalsVisibleToAttribute或在C++中使用友元函数

有关更多信息,我推荐Martin Fowler的经典著作“企业架构的模式”。

但是,作为警告,在开始编写自己的映射器之前,我强烈建议使用第三方对象关系映射器工具,如nHibernate或微软的实体框架。我在四个不同的项目中工作过,出于各种原因,我们编写了自己的映射器,并且很容易浪费大量时间来维护和扩展映射器,而不是编写提供最终用户价值的代码。到目前为止,我已经在一个项目中使用了nHibernate,尽管它最初有相当陡峭的学习曲线,但您在早期投入的投资获得了相当大的回报。

票数 7
EN

Stack Overflow用户

发布于 2008-08-12 21:28:10

这是一个典型的问题--将域模型与数据库模型分开。有几种方法可以攻击它,在我看来,这真的取决于你的项目的规模。您可以像其他人所说的那样使用存储库模式。如果你使用的是.net或java,你可以使用NHibernateHibernate

我所做的是使用Test Driven Development,所以我首先编写我的UI和模型层,数据层是模拟的,所以UI和模型是围绕特定于领域的对象构建的,然后我将这些对象映射到我使用的数据层的任何技术。让数据库决定应用程序的设计,首先编写应用程序,然后再考虑数据,这是一个非常糟糕的想法。

ps这个问题的标题有点误导人

票数 5
EN

Stack Overflow用户

发布于 2008-08-12 21:34:47

@Ice^^热度:

您所说的数据层不应该知道业务逻辑层是什么意思?如何用数据填充业务对象?

UI向业务层中的ServiceClass请求服务,即获取由具有所需参数数据的对象过滤的对象列表。

然后,ServiceClass在数据层中创建一个存储库类的实例,并调用GetList(ParameterType过滤器)。

然后,数据层访问数据库,提取数据,并将其映射为“域”程序集中定义的通用格式。

BL不再处理此数据,因此它将其输出到UI。

然后,UI想要编辑项目X。它将项目(或业务对象)发送到业务层中的服务。业务层验证对象,如果对象正常,则将其发送到数据层进行存储。

UI知道业务层中的服务,而业务层又知道数据层。

UI负责将用户数据输入映射到对象和从对象映射,数据层负责将db中的数据映射到对象和从对象映射数据。业务层保持纯粹的业务。:)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9240

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档