0

我有一个现实世界的问题,我将尝试将其抽象为一个说明性示例。

所以想象一下我在树中有数据对象,父对象可以访问子对象,子对象可以访问父对象:

// Interfaces
interface IParent<TChild> { List<TChild> Children; }
interface IChild<TParent> { TParent Parent; }

// Classes
class Top : IParent<Middle> {}
class Middle : IParent<Bottom>, IChild<Top> {}
class Bottom : IChild<Middle> {}

// Usage
var top = new Top();
var middles = top.Children; // List<Middle>
foreach (var middle in middles) {
    var bottoms = middle.Children; // List<Bottom>
    foreach (var bottom in bottoms) {
        var middle = bottom.Parent; // Access the parent
        var top = middle.Parent; // Access the grandparent
    }
}

所有三个数据对象都具有保存在两个数据存储(例如数据库和 Web 服务)中的属性,它们需要反映并与存储同步。有些对象只从 Web 服务请求,有些只向它写入。

数据映射器

我最喜欢的数据访问模式是Data Mapper,因为它将数据对象本身与与数据存储的通信完全分开:

class TopMapper {
    public Top FetchById(int id) {
        var top = new Top(DataStore.TopDataById(id));
        top.Children = MiddleMapper.FetchForTop(Top);
        return Top;
    }
}

class MiddleMapper {
    public Middle FetchById(int id) {
         var middle = new Middle(DataStore.MiddleDataById(id));
         middle.Parent = TopMapper.FetchForMiddle(middle);
         middle.Children = BottomMapper.FetchForMiddle(bottom);
         return middle;
    }
}

这样我可以每个数据存储有一个映射器,并从我想要的映射器构建对象,然后使用我想要的映射器将其保存回来。

这里有一个循环引用,但我想这不是问题,因为大多数语言只能存储对对象的内存引用,因此实际上不会有无限数据。

这样做的问题是,每次我想构造一个新的Top, Middleor时,它都需要在该对象的or属性Bottom中构建整个对象树,其中包含所有数据存储请求和所需的内存使用情况。在现实生活中,我的树比这里展示的要大得多,所以这是个问题。ParentChildren

对象中的请求

在此对象请求它们Parent的 s 和Children它们自己:

class Middle {
    private List<Bottom> _children = null; // cache
    public List<Bottom> Children {
        get {
            _children = _children ?? BottomMapper.FetchForMiddle(this);
            return _children;
        }
        set {
            BottomMapper.UpdateForMiddle(this, value);
            _children = value;
        }
    }
}

我认为这是存储库模式的一个例子。那是对的吗?

这个解决方案看起来很简洁——数据只在您需要时从数据存储中请求,然后如果您想再次请求它,它会存储在对象中,避免进一步的请求。

但是,我有两个不同的数据源。有一个数据库,但也有一个 Web 服务,我需要能够从 Web 服务创建一个对象并将其保存回数据库,然后从数据库再次请求它并更新 Web 服务。

这也让我感到不安,因为数据对象本身不再对数据源一无所知。我们引入了一个新的依赖项,更不用说循环依赖项了,这使得测试变得更加困难。这些对象现在掩盖了它们与数据库的通信。

其他解决方案

是否有任何其他解决方案可以解决多个商店问题,但也意味着我不需要每次都构建/请求所有数据?

4

1 回答 1

0

你真的在问两个不相关的问题。是的,存储库模式应该导致从商店中提取项目,其中项目本身(实体)对商店一无所知。因此,您通常拥有实现 CRUD 的存储库,并且每次您需要一个实体时,您都可以从那里获取它们。我不明白映射器的意义,也不明白你为什么需要那个中产阶级..?

第二个问题是如何处理可能不是一次全部构建的大树。由于您使用设计模式对此进行了标记,因此建议树类应该实现Composite而不是“映射器”,您应该有一个Builder是合适的。然后那个 Builder 必须能够分阶段构建事物。这是一个有趣的问题。在依赖注入的世界中, OpenSessionInView使这更加复杂。

尝试考虑一个没有仅用于位置区分的类的版本,我认为 Composite 将使这成为可能。

于 2012-10-30T15:13:08.393 回答