开发者

Repository pattern, one interface, multiple classes

Given this code

public interface IRepositor开发者_如何学Cy<T>
{
    IQueryable<T> GetAll();
}

and this

public class XmlProductRepository : IRepository<Product>
{
    private const string RelativePath = "~/data/products.xml";

    public string Filename { get; private set; }
    public XmlLoader Loader { get; private set; }

    public XmlProductRepository(HttpContextBase httpContext, XmlLoader loader)
    {
        Filename = httpContext.Server.MapPath(RelativePath);
        Loader = loader;
    }

    public IQueryable<Product> GetAll()
    {
        return Loader.Load<ProductCollection>(Filename).AsQueryable();
    }
}

what would you do to support many object types (apart from Product, additional 20 types like Plugin, Extension, Page, Section, etc.)? The implementation of the interface is the same for all object types, the only thing that is different is the RelativePath - we want to save different types into different folders organised by their type name, like so

  • ~/data/Product/...
  • ~/data/Plugin/...
  • ~/data/Page/...

So assume the only thing that changes is the path. Obviously we don't want to make a repository class for each one of those object types and copy the same code into each one of those classes. We just want to construct the path based on the object used for T.


Can you make the XmlRepository generic and use typeof to get the name of the xml file?

public class XmlRepository<T> : IRepository<T>
{
    private readonly string RelativePath;

    public string Filename { get; private set; }
    public XmlLoader Loader { get; private set; }

    public XmlRepository( HttpContextBase httpContext, XmlLoader loader )
    {
        RelativePath = string.Format( "~/data/{0}.xml" + typeof( T ).Name );
        Filename = httpContext.Server.MapPath( RelativePath );
        Loader = loader;
    }

    public IQueryable<T> GetAll()
    {
        return Loader.Load<List<T>>( Filename ).AsQueryable();
    }
}


public class XmlRepository<TEntityType> : IRepository<TEntityType> 
{ 

Type t = typeof(TEntityType);
private const string RelativePath = String.Format("~/data/{0}.xml",t.Name); 

public string Filename { get; private set; } 
public XmlLoader Loader { get; private set; } 

public XmlProductRepository(HttpContextBase httpContext, XmlLoader loader) 
{ 
    Filename = httpContext.Server.MapPath(RelativePath); 
    Loader = loader; 
} 

public IQueryable<TEntityType> GetAll() 
{ 
    return Loader.Load<List<TEntityType>>(Filename).AsQueryable(); 
} 

}


You could create an abstract base class, like:

public abstract class Repository<T> : IRepository<T>
{
    public string Filename { get; private set; }
    public XmlLoader Loader { get; private set; }

    protected Repository<T>(HttpContextBase httpContext, XmlLoader loader, string relativePath)
    {
        Filename = httpContext.Server.MapPath(relativePath));
        Loader = loader;
    }

    public abstract IQueryable<T> GetAll();
}

XmlProductRepository:

public class XmlProductRepository : Repository<Product>
{
    public XmlProductRepository(HttpContextBase httpContext, XmlLoader loader)
             : base( httpContext, loader, "~/data/products.xml" ) {}

    public IQueryable<Product> GetAll()
    {
        return Loader.Load<ProductCollection>(Filename).AsQueryable();
    }
}

Unfortunately it seems, that you need to specify ProductCollection --> implement GetAll(). Without this ProductCollection you could move the GetAll() method to the base class as well.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜