In questo articolo Mark Seemann spiega come Onion / Hexagonal Architecture (o Ports and Adapters) sono in qualche modo simili a un'architettura a strati quando viene applicato il principio di inversione di dipendenza (DIP). Soprattutto se consideri le affermazioni fatte in questo articolo a tenere l'acqua, penso che sia tutto abbastanza chiaro e diretto.
Ad ogni modo c'è una citazione su Porte e adattatori che mi ha fatto riflettere sul modo in cui ho strutturato le mie lezioni in passato
The components in the inner hexagon have few or no dependencies on each other, while components in the outer hexagon act as Adapters between the inner components, and the application boundaries: its ports.
Dato che mi piacerebbe implementare alcune logiche di app, chiamate App
qui di seguito (non un nome troppo significativo, comunque), che ci consentirebbe di visualizzare un elenco di dipendenti filtrati. La visualizzazione di un elenco di dipendenti sarebbe fornita da una porta
public interface IEmployeeListProvider
{
EmployeeList GetEmployees();
}
e la persistenza sarebbe un'altra porta
public interface IEmployeeRpository
{
IEnumerable<Employee> GetAllEmployees();
void AddEmployee(Employee employeeToAdd);
void UpdateEmployee(Employee employeeToUpdate);
// further method signatures
}
Ora implementerei la mia logica aziendale
class App : IEmployeeListProvider
{
// most likely the filters or filter conditions would be injected.
// and the IEmployeeRepository anyway
public EmployeeList GetEmployees()
{
var employees = employeeRepository.GetAllEmployees();
var filteredEmployees = FilterEmployees(employees);
return EmployeeList.FromEnumerable(filteredEmployees);
}
private IEnumerable<Employee> FilterEmployees(IEnumerable<IEmployee> employees)
{
// elided
}
}
Fondamentalmente questo è il modo in cui ho capito le porte e gli adattatori come proposto da Alistair Cockburn . Ad ogni modo, questa implementazione contraddice in qualche modo la citazione di Mark Seeman (vedi sopra), poiché App
dipende da bot sulle IEmployeeRepository
e sulle porte IEmployeeListProvider
. Ovviamente sarebbe possibile ristrutturare il design per utilizzare una porta filtro
public interface IEmployeeFilter
{
IEnumerable<Employee> FilterEmployees(IEnumerable<Employee> employees);
}
e fai qualcosa di simile dall'interfaccia utente
IEmployeeFilter filter = ...; // however this is constructed
IEmployeeRepository repository = ...;
// ...
var employees = filter.FilterEmployees(repository.GetAllEmployees());
ma questo mi sembra sbagliato per diversi motivi:
- L'interfaccia utente dipenderà da una porta DAL
- Stiamo potenzialmente spostando la logica verso il codice dell'interfaccia utente
- È molto probabile che l'interfaccia utente diventerà un "maiale dipendente"
Ho sbagliato l'intera citazione di Mark Seeman? C'è qualche altra parte che ho fondamentalmente sbagliato?