Ich versuche, einen neuen architektonischen Ansatz für die Kommunikation zwischen den Schichten zu implementieren, indem ich abstrakte Modelle und Dekoratoren verwende.Dekoratoren für Inter-Layer-Kommunikation
Wenn wir die Schichten einer monolithischen Anwendung entwerfen, hätten wir normalerweise eine Anwendungsschicht (Controller), eine Domänenschicht (Business) und eine Infrastrukturschicht (Persistenz). Diese Schichten kommunizieren miteinander über eine konkrete Modelldefinition, die beim Lesen aus einer Datenbank durch ein Repository, dann zu einem Service und schließlich zu einem Controller navigiert, der sie an einen Client ausgibt.
Das heißt, lassen Sie uns auf den Punkt ...
Normalerweise muss das Infrastrukturmodell nicht das gleiche wie das Geschäftsmodell, die auch nicht das gleiche wie das UI-Modell sein muss. Das Infrastrukturmodell kann sich nur auf die Struktur des Ziel-Repositorys beziehen, der Domänen-Layer kann sich nur auf den Geschäftsbetrieb beziehen, und der UI-Layer muss nur die Clients und Daten lesen/eingeben.
Alle diese Schichten müssen eine Abstraktion voneinander "verstehen" oder sogar bidirektionale Wertezuordnung (oder DTOs) implementieren, um zwischen ihnen zu kommunizieren. Mapping/DTO ist ein schlechter Ansatz, da wir für die Datenzuordnung unnötige Verarbeitung benötigen.
Also, hier ist, was ich versuche zu tun: Separate Schichten mit Dekoratoren für die Kommunikation.
In diesem Ansatz würden wir abstrakte Komponenten und seine Dekoratoren auf einem gemeinsamen Modul haben, und jede Schicht hätte ihren eigenen Dekorator.
Eg .:
- AbstractFoo ist eine Abstraktion;
- FooDecorator implementiert AbstractFoo und umschließt auch ein AbstractFoo;
- FooEntity ist ein Infrastrukturmodell, das FooDecorator implementiert und Ausdauer Sachen
- FooBusiness ist ein Geschäftsmodell, das FooEntity Dekorateur implementiert Griff und Business-Sachen
- FooView ist ein Controller-Modell, das FooBusiness Dekorateur implementiert und Griff UI Felder, Codierung behandeln und ... etc
Mit diesem Ansatz konnten wir:
- haben nur 1 Objekt im Speicher hält Foo Informationen, aber e sehr Schicht "Köpfe, es ist ein eigenes Geschäft".
- Trennen Sie die Schichten in verschiedenen Modulen, sodass das Unternehmen nur die infra importiert und die Anwendungsschicht nur das Geschäft importiert.
- Wir könnten Stubs für dumme Logiken verteilen, ohne unsere Domain zu vergeben, wie einen shopping-cart Service, der nur die Zusammenfassung eines Produkts kennen muss, aber nicht das Domain-Objekt selbst.
- Wir könnten verschiedene Teams haben, die in verschiedenen Schichten der Anwendung ohne Konflikt arbeiten.
Hier ist ein Beispiel auf Papier:
Also ... was ich verlangen Vorschlag ist, Tipps und einigen Meinungen, wenn es ein guter Ansatz ist.
[UPDATE # 1]:
meine Frage zu vereinfachen, werde ich einen Anwendungsfall schreiben unter:
gemeinsam genutzter Komponenten:
// Abstract Foo
public abstract class AbstractFoo {
protected Long id;
protected String color;
protected LocalDateTime lastModified;
protected Long getId();
protected String getColor();
protected void setId();
protected void setColor();
}
// Abstract Decorator(wraps foo)
public abstract class FooDecorator extends AbstractFoo {
private final Foo foo;
protected FooDecorator(Foo foo) { this.foo = foo; }
protected Long getId() {return foo.getId();}
protected String getColor() {return foo.getColor();}
protected LocalDateTime getLastModified() {return foo.getLastModified();}
protected void setId(Long id){foo.setId(id);}
protected void setColor(String color){foo.setColor(color);}
protected void setLastModified(LocalDateTime lastModified){foo.setLastModified(lastModified);}
}
Infrastruktur-Schicht:
// Defines the database model for Foo
// Only concerned about the table structure
@Entity
@Table(name="TBL_FOO")
public class FooEntity extends FooDecorator {
public FooEntity(Foo foo) {
super(foo);
}
@Id @AutoGenerated @Column(name="ID_FOO")
protected Long getId() {
return super.getId();
}
@Column(name="DS_COLOR", length="255")
protected String getColor(){
return super.getColor();
}
@Temporal @Column(name="DT_MODIFIED")
protected LocalDateTime getLastModified(){
return super.getLastModified();
}
}
Schicht
Domain (Geschäft)
public class FooBar extends FooEntity {
public FooBar(Foo foo) {
super(foo);
}
//let's open the ID for the outside world
public Long getId() {
return super.getId();
}
// Paint with a red color
public void paintAs(Color color) {
super.setColor(color.getKey());
}
// Upper level may want to know the current color
public Color getColor() {
return Color.parse(super.getColor());
}
public boolean isModifiedSince(LocalDateTime compare) {
return DateUtils.compareMillis(super.getLastModified(), compare) > 0;
}
public LocalDateTime getLastModified() {
return super.getLastModified();
}
}
Applikation (Ansicht) Schicht
/**
* JSON Eg.:
* {fooBarId: 1, fooBarColor: 'RED'}
*/
public class FooBarView extends FooBar {
public FooBarView(Foo foo) {
super(foo);
}
// Maps field to JSON as 'fooBarId'
@JsonMap("fooBarId");
public Long getId() {
return super.getId();
}
// Maps field to JSON as 'fooBarColor'
@JsonMap("fooBarColor")
public String getColor() {
return super.getColor().toString();
}
}
-
// Pseudo Code
public class FooBarREST {
// '/api/v1/foobar/{id}'
public getFooBar(Long id) {
return new FooBarView(find(id));
}
}
Ich möchte einen Anwendungsfall im Code sehen, um sicherzustellen, dass ich Ihren Standpunkt verstanden habe. Dann würde ich gerne meine Gedanken teilen :) – mgonzalezbaile
Dies ist eine große Frage für [Programmierer] (http://programmers.stackexchange.com/), aber ich denke nicht, dass es hier in SO passt. –
@mgonzalezbaile Ich habe einige Pseudo-Code geschrieben, aber ich konnte nicht in einem anspruchsvolleren Geschäftsablauf denken. – ggdio