Wie der Name schon sagt, ist die domänengesteuerte Entwicklung nicht nur ein Implementierungsmuster, sondern eine Entwicklungsmethode, an der andere Mitglieder als das Entwicklungspersonal beteiligt sind.
Beim Entwurf einer domänengesteuerten Entwicklung wird die Software in den folgenden drei Schichten entworfen.
--Anwendungsschicht
Warum machst du so eine Trennung? Plötzlich kann die Entwicklung der mobilen App-Version beginnen, und plötzlich ist die Datenbank möglicherweise keine RDB mehr. In einem solchen Fall kann das Domänenwissen zwischen Software derselben Domäne wiederverwendet werden, und dies schließt die Domänenschicht ein.
** Anwendungsschicht **
--Hauptfunktion
** Domain-Schicht **
** Infrastrukturschicht **
--Repository
Sie können sehen, dass die Implementierungsklasse des Repositorys die Infrastrukturschicht ist. Aber warum ist die Schnittstelle eine Domänenschicht? Dies liegt daran, dass die Implementierung der Domänenschicht, die sie aufruft, unweigerlich von der Infrastrukturschicht abhängt, wenn eine Schnittstelle eine Infrastrukturschicht ist. Mit anderen Worten, Sie können die zu verwendende Infrastrukturbibliothek nicht auswählen.
Er erklärte, dass die Schnittstelle des Repositorys in die Domänenschicht gestellt wird, damit die Domänenschicht nicht von der Infrastrukturschicht abhängt. Wo initialisieren Sie eine Instanz des Repositorys, die Implementierungswissen enthält? Einfach ausgedrückt scheint es keine andere Wahl zu geben, als es auf der Anwendungsebene zu initialisieren und an den Domänendienst weiterzugeben. Wenn Sie jedoch Spring DI verwenden und eine Implementierungsklasse als Komponente deklarieren, die die Domänendienstklasse und die Schnittstelle erbt, löst Spring DI dieses Problem. Es ist nicht erforderlich, ein Factory-Muster oder "ApplicationContextAware" vorzubereiten.
@Repository
public class Repository extends IRepository {
...
}
Verwenden Sie den Konstruktor "@ Autowired" anstelle des Feldes "@ Autowired", um die Abhängigkeit aufzulösen. Es erleichtert das Schreiben von Unit-Tests. Es kann einfacher mit Lomboks "@ RequiredArgsConstructor" geschrieben werden.
@Service
@RequiredArgsConstructor
public class Service {
private final IRepository repository;
}
IRepository mockRespository = new MockRepository();
var service = new Service(mockRespotory);
Ich schrieb, dass die Software in drei Schichten entworfen wurde, aber sollte das Maven-Modul auch in drei Schichten unterteilt werden? Wenn die Software einzeln ist, reicht es aus, sie in Pakete aufzuteilen.
Bereiten Sie im Gegenteil beim Teilen des Moduls ein übergeordnetes Modul vor
/pom.xml
<modules>
<module>./web</module>
<module>./mobile</module>
<module>./domain</module>
<module>./infrastructure</module>
</modules>
Wie
/application/pom.xml
<parent>
<groupId>me.yong_ju.application</groupId>
<artifactId>parent</artifactId>
<version>...</version>
<relativePath>../</relativePath>
</parent>
...
<dependencies>
<dependency>
<groupId>me.yong_ju.application</groupId>
<artifactId>domain</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>me.yong_ju.application</groupId>
<artifactId>infrastructure</artifactId>
<version>...</version>
</dependency>
</dependencies>
Du kannst es schaffen. Wenn Sie das untergeordnete Modul zuerst im übergeordneten Modul definieren und es der Abhängigkeit hinzufügen, wird es lokal und nicht im Maven-Repository abgerufen. (Die Versionen müssen jedoch übereinstimmen)
Wenn Sie das Paket in drei Ebenen aufteilen, tritt sofort ein Problem auf. Das liegt daran, dass wir "@ SpringBootApplication" in das Anwendungspaket einfügen, sodass der Komponentenscan von Spring nur Komponenten der Anwendungsebene injiziert.
was ist zu tun. Sie können "scanBasePackages" verwenden, um die Pakete, die Sie scannen möchten, in die obere Ebene zu ändern. Wir empfehlen dies jedoch nicht.
Hier haben wir beschlossen, eine Konfigurationsklasse mit aktiviertem Komponentenscan in der Domänen- und Infrastrukturebene vorzubereiten und die von der Anwendung verwendete Konfiguration explizit mit "@ Import" zu versehen.
@Configuration
@ComponentScan
public class DomainConfiguration {
...
}
@Configuration
@ComponentScan
public class InfrastructureConfiguration {
...
}
@SpringBootApplication
@Import({ DomainConfiguration.class, InfrastructureConfiguration.class })
public class Application {
...
}
Ein Muster, in dem ein Dienst, den Sie häufig sehen, nur noch ein Wrapper für das Repository ist. Es sollte in sinnvollen Betriebseinheiten gewartet werden, und wenn es noch nicht bekannt ist, ist es noch schneller, es in einen Service umzuwandeln. (In diesem Zusammenhang sehe ich häufig Muster, die in einer völlig bedeutungslosen Bedieneinheit "@ Transactional" waren.)
Ich persönlich denke, dass Implementierungsmuster im Allgemeinen ein Werkzeug sind, um das Denken zu beenden und gleichzeitig schwerwiegende Designfehler bei der Softwareentwicklung mit schlechten Planungsaussichten zu vermeiden. Daher ist es ein Chaos, Zeit damit zu verschwenden, nach den besten Praktiken für alles zu suchen. Und Java und seine peripheren Frameworks entwickeln sich ständig weiter. In einigen Fällen können sie für eine weniger redundante und sicherere Implementierung verwendet werden.
Wenn ich Freizeit habe, werde ich mich auf das konzentrieren, was ich verstanden habe.
Recommended Posts