在现有代码库中实现Mock Repositories

时间:2009-12-10 21:15:48

标签: design-patterns repository factory

因此,对象模型相当复杂和分层。 祖父接受是由祖父工厂创建的,该工厂在其构造函数中接受祖父存储库。

一切都很好。

现在,当祖父需要加载它时,孩子们是如何做到的?

它如何了解ChildFactory和ChildRepository?它应该不正确?

但是它如何加载它们呢?我不认为你将ChildFactory传递给祖父构造函数,就好像你有孙子(这个应用程序那样)你也需要传递一个GrandchildFactory!

你是否实例化了某种具有其中所有不同类型工厂的EverythingFactory并将其传递给每个构造函数并且他们使用了他们关心的那个?

或者是否有一些我只是没有看到的简单解决方案?

目前所有对象都调用web服务来加载他们的数据,我正试图将其拉出并创建一个可以模拟用于测试目的的Repository接口。

修改 忽略工厂,我不需要它们,我想我只是过于复杂化了。

目前,对象通过分散在对象中的webservice调用来加载其数据和子数据。

大多数对象构造函数都标记为私有,并且它们具有静态方法,如“LoadByID(int)”,以便从db中检索它们。

然后当引用包含它的子方法的属性时,如果它的私有“子列表”变量为空,则调用Child.GetAllChildrenFor(this);这是Child的静态方法,“this”是Parent类。它调用webservice,创建所有Childs,并返回它们的列表,每个列表都引用它的父级。

我知道这不是很正确...但我不知道我哪里出错了,或者如何纠正它以便能够删除webservice调用并放入一个可以是真实的Repository界面或者模拟......在我设置的代码中使用哪个地方!

EDIT2: 代码是目前这些行的代码

public interface IEntity
{
    int ID { get; set; }
}

public class Parent : IEntity
{
    public int ID { get; set; }

    private Children children;
    public Children Children 
    { 
        get 
        {
            if (this.children == default(Children)) 
            {
                this.children = Children.GetChildrenFor(this);
            }
            return this.children;
        }
    }
}

public class Children : List<Child>
{
    private Children() { }

    public static Children GetChildrenFor(Parent parent)
    {
        Children children = new Children();

        DataSet childrenDataSet = new DataSet();
        using (webservice) 
        {
            childrenDataSet = webservice.Retrieve(parent.ID)
        }

        if (childrenDataSet.HasRows())
        {
            foreach (DataRow dr in childrenDataSet.Tables[0].Rows)
            {
                Child rr = Child.LoadByDataRow(dr);
                rr.Parent = parent;
                children.Add(rr);
            }
        }

        return children;
    }
}

public class Child : IEntity 
{
    public Parent Parent { get; set; }
    public int ID { get; set; }

    internal static Child LoadByDataRow(DataRow dr)
    {
        Child child = new Child();

        child.ID = dr.Field<int>("ID");
        child.GrandChild = GrandChildren.GetGrandChildrenFor(this);

        return child;
    }
}

2 个答案:

答案 0 :(得分:1)

将此代码从静态方法中分解出来并使其可模拟的一种方法是创建一个IRepository接口,该接口定义将为您的实体提供的类的合同。

public interface IRepository {
    Parent GetParent(int parentId);
    List<Child> GetChildrenByParent(int parentId);
    // ...
}

接下来,将实体更改为在其构造函数中需要IRepository

public class Parent: IEntity {
    private IRepository repository;
    public Parent(IRepository repository) {
        this.repository = repository;
    }
    // ...
}

具体的IRepository实现将包含调用Web服务并将其结果映射到每个实体的代码;它在构造实体时必须自行传递,如下所示:

public class ConcreteRepository: IRepository {
    public Parent GetParent(int parentId) {
        Parent parent = new Parent(this);
        // Call web service, perform mapping, etc.
    }
}

像这样构造的实体可以根据需要使用存储库 - 例如,在Parent.Children get访问器中。您的应用程序将使用真实的存储库,而单元测试可以提供模拟或存根。

答案 1 :(得分:0)

创建工厂的层次结构。 ChildFactory继承了继承GrandfatherFactory的FatherFactory。也许工厂可以模板化,或者你可以使用抽象工厂设计模式。