Best Practice: Common Interfaces

I made a general interface, for example:

public interface IDatabaseElement<T> { IList<T> GetAll(); T Get(id); void Save(T element); void Delete(int id); } 

If I have, for example, two elements ("A person and a store") that use only the above methods, what is considered best practice?

A: Creating a new interface for each element, for example:

 public interface IPerson : IDatabaseElement<Person> { } public interface IStore : IDatabaseElement<Store> { } 

and then my classes are like:

 public class Person : IPerson { .... } public class Store : IStore { .... } 

and with instantiation variables:

 IPerson person = new Person(); IStore store = new Store(); 

or B: using common interfaces, like:

 public class Person : IDatabaseElement<Person> { .... } public class Store : IDatabaseElement<Store> { .... } 

and when setting variables:

 IDatabaseElement<Person> person = new Person(); IDatabaseElement<Store> store = new Store(); 

What is considered best practice?

+4
source share
1 answer

There is a well-known design pattern for calling IDatabaseElement<T> ; It is called a Model Template . So, start by renaming the IDatabaseElement<T> to:

 public interface IRepository<TEntity> { ... } 

Also, since you are defining an IPerson interface, it seems like you are defining an interface for a Person object instead of a repository.

Hiding your entity behind an interface is bad practice because your objects are data objects, and interfaces are only needed for abstract behavior.

So instead of calling the IPerson interface IPerson start by calling IPersonRepository .

On the other hand, if your Person class does contain data (e.g. FirstName , LastName , Age , etc.), then you are mixing responsibilities. Your entities do not need to know how to extract themselves (or other instances !!!) from the database. Retrieving data from a database and storing data are two different responsibilities, and you must separate them (give each class its own responsibility). Your system will soon become unbearable if you violate the principle of single responsibility .

Now, creating a specific interface for each type of repository (e.g. IPersonRepository ) is a bad idea. The main reason for having a common abstraction is that it greatly simplifies adding additional behavior (for example, problems with cross-references), as it allows you to define one common decorator, for example: AuditTrailingRepositoryDecorator<T> . But when you allow the implementation of the repository of your face to inherit from IPersonRepository , you can no longer wrap it with a universal decorator, simply because all the methods you define on IPersonRepository will no longer be available. It also makes writing unit tests easier, because in your test case you only need to create one common fake implementation of IRepository<T> .

If you are not interested in adding cross-referencing problems and being able to easily test your code base, you can go with specific (non-generic) interfaces such as IPersonRepository and IStoreRepository .

+7
source

Source: https://habr.com/ru/post/1480332/


All Articles