Je pense résumer les anti-patterns que je vois souvent en travaillant. Cette fois, c'est une violation de la loi de Demeter. Le code est Scala, mais c'est fondamentalement le même pour Ruby, Python et Java.
Les sujets sont ci-dessous.
La loi de Demeter est que vous ne devez rien utiliser d'autre que "directement instancié" ou "passé comme argument".
class Profile(name: String, age: Int) {
def showProfile(): Unit = println(s"my name is $name (age: $age)")
}
class Applicant(id: String, val profile: Profile)
object Order {
//Viole la loi de Déméter
def showApplicant(applicant: Applicant): Unit = {
applicant.profile.showProfile()
}
}
ʻApplicantest passé comme argument, mais dans la méthode, Cela enfreint parce que la méthode
showProfile ()est exécutée après avoir récupéré le
profile dans ʻapplicant.profile
.
ʻApplicant.profile.showProfile () parce que je veux le faire Je pense que vous devriez hésiter à ajouter
val like
class Applicant (id: String, val profile: Profile) ʻet ** publier les propriétés avec getter **.
Le formulaire que vous souhaitez appeler est le suivant.
def showApplicant(applicant: Applicant): Unit = {
applicant.showProfile()
}
Ici, ce qui suit est décrit.
class Profile(name: String, age: Int) {
def showProfile(): Unit = println(s"my name is $name (age: $age)")
}
//Le candidat hérite du profil
class Applicant(id: String, name: String, age: Int) extends Profile(name, age)
object Order {
def showApplicant(applicant: Applicant): Unit = {
applicant.showProfile()
}
}
↑ Cela semble étrange, alors corrigez-le avec la méthode de transfert.
class Profile(name: String, age: Int) {
def showProfile(): Unit = println(s"my name is $name (age: $age)")
}
//Puisque le profil n'a plus besoin d'être publié par les getters
//J'ai enlevé le val.
class Applicant(id: String, profile: Profile) {
//Méthode de transfert
def showProfile(): Unit = profile.showProfile()
}
object Order {
def showApplicant(applicant: Applicant): Unit = {
applicant.showProfile()
}
}
De là, considérons le test de la méthode ʻOrder.showApplicant () `modifiée par la ** méthode de transfert **.
object SimpleTest extends App {
//Créez l'objet requis
val profile = new Profile("taro", 22)
val applicant = new Applicant("001", profile)
//Exécuter la méthode testée
Order.showApplicant(applicant)
}
Dans l'exemple ci-dessus, il est facile de créer une instance ʻApplicant, mais par exemple, considérons le cas où ʻApplicant
agrège diverses classes et l'instanciation est délicate, comme indiqué ci-dessous.
L'important est que ** la cible du test soit la méthode ʻOrder.showApplicant () `, qui est une méthode de transfert, donc c'est bien si vous pouvez confirmer que vous l'avez appelée. Cela signifie **.
object ComplexTest extends App {
//Instanciation complexe
val profile1 = ...
val profile2 = ...
val profile3 = ...
val applicant = new Applicant("001", profile1, profile2, profile3, ...)
//Je veux juste exécuter la méthode testée,
//La génération d'instances est un problème.
Order.showApplicant(applicant)
}
Tant que la méthode ʻOrder.showApplicant () peut être exécutée, le contenu de l'argument ʻapplicant
peut être n'importe quoi.
Donc, prenez en sandwich l'interface pour que ʻOrder.showApplicant () `dépende du résumé.
//Gardez-le abstrait
trait IApplicant {
def showProfile(): Unit
}
class Applicant(id: String, profile: Profile) extends IApplicant {
def showProfile(): Unit = profile.showProfile()
}
object Order {
//Le type de candidat est désormais IApplicant et dépend de l'abstraction.
def showApplicant(applicant: IApplicant): Unit = {
applicant.showProfile()
}
}
Le ʻapplicantrequis pour l'argument de la méthode ʻOrder.showApplicant ()
peut être généré comme suit, ce qui rend le test un peu plus facile.
object RefactorComplexTest extends App {
//Instanciation complexe
val applicant = new IApplicant {
override def showProfile(): Unit = println("Allons. adapté. Allons")
}
Order.showApplicant(applicant)
}
Si vous continuez à violer la loi de Demetel comme indiqué ci-dessous, ce sera difficile à tester, donc je pense personnellement que si vous enfreignez la loi de Demetel, vous devriez la réparer.
Vous pouvez le tester en utilisant une maquette, mais je pense personnellement qu'il est préférable de revoir la conception avant d'utiliser la maquette.
def showApplicant(applicant: Applicant): Unit = {
//Il est difficile de tester si vous continuez à enfreindre la loi de Demeter
applicant.profile.showProfile()
}
Recommended Posts