装饰器模式 - 向接口添加方法

时间:2014-06-25 09:59:29

标签: c# decorator

我目前正在努力实施IUnitOfwork。 我们假设我有一个有两种方法的接口:

public interface IRepository<TEntity, in TKey>
{

    TEntity Get(TKey id);

    IQueryable<TEntity> All();
}

现在,假设我有几个实现此接口的类(实体)。 但是,某些实体可能需要使用其他方法进行查询,例如GetById(int id)。

这可以通过创建一个名为IRepositoryWithGetById

的新接口轻松解决。
public interface IRepository<TEntity, in TKey>
{

    TEntity Get(TKey id);

    TEntity GetById(int id);

    IQueryable<TEntity> All();
}

这将是导致维护代码的噩梦。 我正在考虑使用装饰器模式,但我找不到一个好的解决方案。

注意:我正在使用接口,因为我应该可以模拟它。

正如用户所建议的那样,我正在使用接口继承,所以这里是更新后的代码:

public class Wrapper
{
    public IRepository standardRepository = new Repository();
    public IDeleteRepository deleteRepository = new DeleteRepository();
    public ICreateRepository createRepository = new CreateRepository();    
}

public class Repository : IRepository
{
    public void GetAll() { }
    public void GetById(int id) { }
}

public class DeleteRepository : Repository, IDeleteRepository
{
    public void Delete() { }
}

public class CreateRepository : Repository, ICreateRepository
{
    public void Create() { }
}

public interface IRepository
{
    void GetAll();
    void GetById(int id);
}

public interface IDeleteRepository : IRepository
{
    void Delete();
}

public interface ICreateRepository : IRepository
{
    void Create();
}

任何知道我如何解决这个问题的人?

3 个答案:

答案 0 :(得分:0)

我认为KrishnaDhungana建议的解决方案运行正常。这是一个我理解的例子,以简单的班级学生为例。构建存储库很容易,并测试是否注入了实现方法......

public class Student
{
    int NoOfParties;
    int NoOfHangOvers;
}

public interface IRepo<T>
{
    IEnumerable<T> GetAll();
    T GetByID();
}

public interface IRepoCreate<T>
{
    Int32 Create();
}

public interface IRepoDelete<T>
{
    void Delete();
}

public interface IStudentRepo : IRepo<Student>, IRepoCreate<Student>, IRepoDelete<Student>
{
    IEnumerable<Student> GetAll();
    Student GetByID();
    int Create();
    void Delete();
    Student GetByParty();
}

public class MSSQLStudentRepo : IStudentRepo
{
    public IEnumerable<Student> GetAll() { \\stuff }
    public Student GetByID() { \\stuff }
    public int Create() { \\stuff }
    public void Delete() { \\stuff }
    public Student GetByParty() { \\stuff }
} 

public class MySQLStudentRepo : IStudentRepo
{
    public IEnumerable<Student> GetAll() { \\stuff }
    public Student GetByID() { \\stuff }
    public int Create() { \\stuff }
    public void Delete() { \\stuff }
    public Student GetByParty() { \\stuff }
}

public void ImplementationExample()
{
    IStudentRepo Repo = new MSSQLStudentRepo();
    var Bob = Repo.GetByParty();
}   

答案 1 :(得分:0)

在装饰器模式中,可能没有其他方法。装饰器模式意味着方法将保持相同但行为可能会更改。我正在写一篇关于它的博客,我会在完成后更新这个回复。

以下代码可能会对您有所帮助,因为所有函数都可以轻松放入sigle类中,您可以将它强制转换为相应的返回代码。

using System.Linq;

public interface IRepository<TEntity, in TKey>
{

    TEntity Get(TKey id);

    IQueryable<TEntity> All();
}

public interface IRepository
{
    void GetAll();
    void GetById(int id);
}

public interface IDeleteRepository : IRepository
{
    void Delete();
}

public interface ICreateRepository : IRepository
{
    void Create();
}


public class Wrapper
{
    private readonly CombinedRepository standardRepository = new CombinedRepository();

    public IRepository Repository
    {
        get { return standardRepository; }
    }

    public ICreateRepository CreateRepository
    {
        get { return standardRepository; }
    }

    public IDeleteRepository DeleteRepository
    {
        get { return standardRepository; }
    }
}

public class CombinedRepository : IRepository, IDeleteRepository, ICreateRepository
{
    public void GetAll()
    {
    }

    public void GetById(int id)
    {
    }

    public void Delete()
    {
    }

    public void Create()
    {
    }
}

答案 2 :(得分:0)

我认为abstract类适用于需要模拟的存储库,virtual实现可以根据需要覆盖。

public interface IRepository<TEntity, in TKey>
{
    TEntity Get(TKey id);
    TEntity GetById(int id);
    IQueryable<TEntity> All();
}

public abstract class Repository : IRepository
{
    public virtual TEntity Get(TKey id) { throw new NotImplementedException(); }
    public virtual TEntity GetById(int id) { throw new NotImplementedException(); }
    public virtual IQueryable<TEntity> All() { throw new NotImplementedException(); }
}

public class FullRepo : Repository
{
    public virtual TEntity Get(TKey id) { /*Implement it!*/ }
    public virtual TEntity GetById(int id) { /*Implement it!*/ }
    public virtual IQueryable<TEntity> All() { /*Implement it!*/ }
}

// No GetById here
public class PartialRepo : Repository
{
    public virtual TEntity Get(TKey id) { /*Implement it!*/ }
    public virtual TEntity GetById(int id) { throw new NotSupportedException(); }
    public virtual IQueryable<TEntity> All() { /*Implement it!*/ }
}

基本上,只实现你需要的东西,接口/抽象类暴露一切。这种方法(至少对我而言)非常易读且易于扩展......并且非常可模仿。

为了避免投掷而不允许使用这些方法,您可以使用ObsoleteAttributeMSDN Reference

// No GetById here
public class PartialRepo : Repository
{
    public virtual TEntity Get(TKey id) { /*Implement it!*/ }
    [Obsolete("This method can't be used by this repository", true)]
    public virtual TEntity GetById(int id) { /*Can be empty*/ }
    public virtual IQueryable<TEntity> All() { /*Implement it!*/ }
}

传递true会使方法的调用成为编译错误(VS会说它已过时&#34;所以它不会完全正确,但它不会尽管如此,仍然可以调用该方法。