如何创建一个灵活的架构,允许我在几个不同的底层数据模型上运行?

时间:2018-02-18 09:54:54

标签: c# generics architecture repository repository-pattern

我正在尝试使用非常灵活的架构创建应用程序。它应该能够轻松地将任何一个层换成不同的组件,只要它粘附在相同的接口上。​​

更具体地说,我的业务逻辑层不应该关心我的数据层如何或在何处检索业务逻辑层请求的数据对象。或者数据层可能需要做什么样的计算才能将数据对象转换为业务层可用的对象。

在我最初尝试解决此问题时,我遇到的问题是,当业务逻辑使用泛型时,数据层不知道如何处理这些类型。例如,假设我的业务逻辑在Car类型上运行。

abstract class Car
{
    public abstract int Wheels { get; set; }
}

虽然我的数据层可能在不同的类型上运行,例如:

class VolvoCar : Car
{
    public override int Wheels { get; set; }
}

class HondaCar : Car
{
    public override int Wheels { get; set; }
}

取决于我当前使用的存储库,VolvoRepository或HondaRepository。这些是通过IoC容器注入的,因此业务逻辑不知道下面是哪个实现。这些类也可能有其他不同的属性,但我的业务逻辑层只关心Car的常见定义,而且不应该担心它是什么类型的汽车。

我的问题是:当我现在想要使用泛型访问数据层时,各层之间的操作类型之间存在脱节。例如,我的业务逻辑可能会将我的存储库问到Get()。但是如果我的存储库是VolvoRepository类型,我真正想要它做的是实例化一个VolvoCar并将其作为Car返回。但我认为我的存储库没有任何简单的推断方法。当然,这可能通过丑陋的手段,如反思或

if (T is Car) return new VolvoCar();

但我正在寻找一种更清洁的方式来做到这一点,“只是有效”。

简而言之,我怎样才能使我的业务逻辑可以简单地操作类型的通用定义,让数据层处理底层数据模型的特定怪癖? (例如,也许Honda将它们的车轮存储成两个一组,因此加载HondaCar意味着将车轮属性乘以2然后再传递到业务层等。)

虽然这主要是一个架构问题,但C#中给出的示例将不胜感激。如果我的想法很遥远的话,我也会接受截然不同的方法。唯一的硬性要求是我需要我的业务逻辑能够在几个不同的数据模型之上工作,这些数据模型都包含大致相同对象(PO​​CO)的定义。然后,数据层组件必须负责处理这些POCO与基础数据模型之间的转换。

1 个答案:

答案 0 :(得分:1)

好吧,你的问题似乎或多或少都清楚了。只要您更喜欢C#示例:

public abstract class TypeUnsafeObject 
{ 
    public abstract object GetObject();
    public abstract void SetObject(object obj);
}

然后:

    public abstract TypeSafeObject<T> : TypeUnsafeObject
    { 
        public abstract T GetTypeSafeObject();
        public abstract void SetTypeSafeObject(T obj);
        public override object GetObject() {
            return GetTypeSafeObject();
        }
        public override void SetObject(object obj) {
            var typeSafeObj = obj as T;
            if (typeSafeObj != null) {
                SetTypeSafeObj(typeSafeObj);
            }
            else {
            // report failure
            }
        }
    }

现在,有些消费者只处理对象(只要对他们来说没问题)。请注意:您的类型不安全层可以绑定到任何不同的类,而不仅仅是object。为了简单起见,我只是试图让事情变得明显。

这是最简单的解决方案。

TypeUnsafeRepo repo = RepoFactory.GetRepoFor<VolvoCar>();
repo.Save();

同时RepoFactory使用强类型对象进行回复。

但说实话,我认为你没有理由需要通用仿制来管理你所描述的复杂性。我建议让事情变得非常简单而且易于理解。