user2859298
user2859298

Reputation: 1443

Separating interfaces and making them more generic

I have an interface to define my records\models

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

Is it best to put the actions into another interface?

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

public interface IStockImport
{
    void CreateItem<IStockItem>;
}

Is there a better way to do this and make it more generic? so i can share the actions interfaces with other records\models?

The other records\models are SalesOrder, Customer, Address.

The overall idea is an Import\Export program, that will create\export sales orders in a number of different accounts packages via an API.

Upvotes: 2

Views: 86

Answers (3)

Matthew Watson
Matthew Watson

Reputation: 109567

This is a common pattern, called the Repository Pattern.

If you want to go down this route, you should create a base interface, Repository<T>, for example:

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);
}

You would make your IStockItem implement an IEntity interface so that it can provide an ID for GetById(), for example:

public interface IEntity
{
    int ID { get; }
}

Then you would implement the repository for a data type such as StockItem by declaring the implementing class. It might start a bit like this:

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

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

    ...

Your code that wanted to get at a repository for a stock item might look like this:

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

This may be overkill for what you want, but it is the general approach.

For full details see this excellent blog post.

Also see this example.

Here's how you might start implementing this pattern for your case:

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);
    }
}

Upvotes: 4

Herm
Herm

Reputation: 2999

you can use a generic interface as well:

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>();
}

Upvotes: 2

toadflakz
toadflakz

Reputation: 7944

You could, but it may not be necessary. Interfaces for method-based classes are best used where you want to have polymorphism related to implementation.

In your case, it seems that what you want is to be able to share common functionality (based on the IStockExport interface) but also provide a polymorphic creation mechanism (based on IStockImport).

I would suggest that you implement an abstract base class for IStockExport which can be inherited for all the various types of IStockItem (due to common interface) and then the derived classes should implement IStockExport as each Create<IStockItem>() implementation will be different but can be used in the same way due to common behaviour (always returns IStockItem object).

Upvotes: 1

Related Questions