LSP : une approche pratique
Partout où je cherche des exemples C# de LSP, les gens ont utilisé des classes et des interfaces imaginaires. Voici l'implémentation pratique de LSP que j'ai mise en place dans un de nos systèmes.
Scénario : Supposons que nous disposions de 3 bases de données (clients des prêts hypothécaires, clients des comptes courants et clients des comptes d'épargne) qui fournissent des données sur les clients et que nous ayons besoin de détails sur le nom de famille d'un client donné. Il se peut que nous obtenions plus d'un détail sur le client à partir de ces 3 bases de données pour un nom de famille donné.
Mise en œuvre :
COUCHE DE MODÈLE D'ENTREPRISE :
public class Customer
{
// customer detail properties...
}
COUCHE D'ACCÈS AUX DONNÉES :
public interface IDataAccess
{
Customer GetDetails(string lastName);
}
L'interface ci-dessus est implémentée par la classe abstraite
public abstract class BaseDataAccess : IDataAccess
{
/// <summary> Enterprise library data block Database object. </summary>
public Database Database;
public Customer GetDetails(string lastName)
{
// use the database object to call the stored procedure to retrieve the customer details
}
}
Cette classe abstraite a une méthode commune "GetDetails" pour les 3 bases de données qui est étendue par chacune des classes de base de données comme indiqué ci-dessous.
L'ACCÈS AUX DONNÉES DES CLIENTS HYPOTHÉCAIRES :
public class MortgageCustomerDataAccess : BaseDataAccess
{
public MortgageCustomerDataAccess(IDatabaseFactory factory)
{
this.Database = factory.GetMortgageCustomerDatabase();
}
}
ACCÈS AUX DONNÉES DU CLIENT DU COMPTE COURANT :
public class CurrentAccountCustomerDataAccess : BaseDataAccess
{
public CurrentAccountCustomerDataAccess(IDatabaseFactory factory)
{
this.Database = factory.GetCurrentAccountCustomerDatabase();
}
}
ACCÈS AUX DONNÉES DES CLIENTS DES COMPTES D'ÉPARGNE :
public class SavingsAccountCustomerDataAccess : BaseDataAccess
{
public SavingsAccountCustomerDataAccess(IDatabaseFactory factory)
{
this.Database = factory.GetSavingsAccountCustomerDatabase();
}
}
Une fois que ces 3 classes d'accès aux données sont définies, nous portons maintenant notre attention sur le client. Dans la couche Business, nous avons la classe CustomerServiceManager qui retourne les détails du client à ses clients.
LA COUCHE COMMERCIALE :
public class CustomerServiceManager : ICustomerServiceManager, BaseServiceManager
{
public IEnumerable<Customer> GetCustomerDetails(string lastName)
{
IEnumerable<IDataAccess> dataAccess = new List<IDataAccess>()
{
new MortgageCustomerDataAccess(new DatabaseFactory()),
new CurrentAccountCustomerDataAccess(new DatabaseFactory()),
new SavingsAccountCustomerDataAccess(new DatabaseFactory())
};
IList<Customer> customers = new List<Customer>();
foreach (IDataAccess nextDataAccess in dataAccess)
{
Customer customerDetail = nextDataAccess.GetDetails(lastName);
customers.Add(customerDetail);
}
return customers;
}
}
Je n'ai pas montré l'injection de dépendance pour rester simple car cela devient déjà compliqué maintenant.
Maintenant, si nous avons une nouvelle base de données de détails sur les clients, nous pouvons simplement ajouter une nouvelle classe qui étend BaseDataAccess et fournit son objet de base de données.
Bien sûr, nous avons besoin de procédures stockées identiques dans toutes les bases de données participantes.
Enfin, le client de CustomerServiceManager
n'appelle que la méthode GetCustomerDetails, transmet le nom de famille et ne se soucie pas de savoir comment et d'où proviennent les données.
J'espère que cela vous donnera une approche pratique pour comprendre le LSP.
10 votes
Voici une façon simplifiée d'y penser en quelques mots : Si je suis LSP, je peux remplacer n'importe quel objet dans mon code par un objet Mock, et rien dans le code appelant ne devra être ajusté ou modifié pour tenir compte de la substitution. LSP est un support fondamental pour le pattern Test by Mock.
0 votes
Il y a d'autres exemples de conformité et de violations dans cette réponse