分离接口并使它们更通用

时间:2015-05-26 11:04:10

标签: c# .net design-patterns

我有一个界面来定义我的记录\ models

public interface IStockItem
{
    string Code { get; set; }
    string Description { get; set; }
    decimal FreeStock { get; set; }
}

最好将动作放入另一个界面吗?

public interface IStockExport
{
    IEnumerable<IStockItem> GetAll();
    IEnumerable<IStockItem> GetStockByCode(string code);
    decimal GetFreeStock(string code);
}

public interface IStockImport
{
    void CreateItem<IStockItem>;
}

有没有更好的方法来做到这一点并使其更通用?所以我可以与其他记录\模型共享动作接口?

其他记录\型号是SalesOrder,Customer,Address。

总体思路是Import \ Export程序,它将通过API在许多不同的帐户包中创建\ export销售订单。

3 个答案:

答案 0 :(得分:3)

您也可以使用通用界面:

public interface IRecordExport<T> where T : IRecordBase
{
  IEnumerable<T> GetAll();
  IEnumerable<T> GetOneByCode(string code);
  decimal GetFree(string code);
}

public interface IRecordImport<T> where T : IRecordBase
{
  void CreateItem<T>();
}

答案 1 :(得分:3)

这是一种常见的模式,称为Repository Pattern

如果你想沿着这条路走下去,你应该创建一个基础界面Repository<T>,例如:

public interface IRepository<T>
{
    void Insert(T entity);
    void Delete(T entity);
    IEnumerable<T> SearchFor(Func<T, bool> predicate);
    IEnumerable<T> GetAll();
    T GetById(int id);
}

您可以让IStockItem实施IEntity接口,以便它可以为GetById()提供ID,例如:

public interface IEntity
{
    int ID { get; }
}

然后,您将通过声明实现类来实现数据类型(如StockItem)的存储库。它可能会有点像这样:

public class Repository<T> : IRepository<T> where T : class, IEntity
{
    protected Table<T> DataTable;

    public Repository(DataContext dataContext)
    {
        DataTable = dataContext.GetTable<T>();
    }

    ...

您想要获取库存商品库的代码可能如下所示:

using (var dataContext = new StockItemDataContext())
{
    var StockItemRepository = new Repository<IStockItem>(dataContext);
    ...

这可能对你想要的东西有点过分,但这是一般方法。

For full details see this excellent blog post

Also see this example.

以下是您如何开始为您的案例实施此模式:

public interface IRepository<T>
{
    void Insert(T entity);
    void Delete(T entity);
    IEnumerable<T> SearchFor(Func<T, bool> predicate);
    IEnumerable<T> GetAll();
    T GetByCode(string code);
}

public interface IStockItem: IEntity
{
    string Description { get; set; }
    decimal FreeStock { get; set; }
}

public sealed class StockItem: IStockItem
{
    public string Code { get; set; }
    public string Description { get; set; }
    public decimal FreeStock { get; set; }
}

public interface IEntity
{
    string Code { get; }
}

public sealed class MyLowLevelDataAccess
{
    public StockItem FindStockItem(string code)
    {
        return null; // Call your API here.
    }

    public void DeleteStockItem(string code)
    {
        // Call your API here.
    }

    public void InsertStockItem(StockItem item)
    {
        // Call your API here.
    }

    public IEnumerable<StockItem> FindAllItems()
    {
        return FindItemsMatching(x => true);
    }

    public IEnumerable<StockItem> FindItemsMatching(Func<StockItem, bool> predicate)
    {
        return null; // Call your API here and return all items matching the predicate.
    }
}

public sealed class StockRepository: IRepository<StockItem>
{
    private readonly MyLowLevelDataAccess _dataAccess;

    public StockRepository(MyLowLevelDataAccess dataAccess)
    {
        _dataAccess = dataAccess;
    }

    public void Insert(StockItem entity)
    {
        _dataAccess.InsertStockItem(entity);
    }

    public void Delete(StockItem entity)
    {
        _dataAccess.DeleteStockItem(entity.Code);
    }

    public IEnumerable<StockItem> SearchFor(Func<StockItem, bool> predicate)
    {
        return _dataAccess.FindItemsMatching(predicate);
    }

    public IEnumerable<StockItem> GetAll()
    {
        return _dataAccess.FindAllItems();
    }

    public StockItem GetByCode(string code)
    {
        return _dataAccess.FindStockItem(code);
    }
}

答案 2 :(得分:1)

你可以,但可能没有必要。基于方法的类的接口最适用于希望与实现相关的多态性的地方。

在您的情况下,您希望能够共享通用功能(基于IStockExport接口),但也提供多态创建机制(基于IStockImport)。< / p>

我建议您为IStockExport实现一个抽象基类,它可以为所有各种类型的IStockItem继承(由于公共接口),然后派生类应该实现{{1因为每个IStockExport实现都会有所不同,但由于常见行为(总是返回Create<IStockItem>()对象),因此可以以相同的方式使用。