# Frage zur Projektarchitektur



## JavaEEDeveloper (16. Jan 2013)

Hallo, ich habe wenig Erfahrung mit der Projektarchitektur von JavaEE Projekten und deshalb möchte ich euch fragen, ob der gewählte Weg von mir ok ist.

Ich erstelle für jede Anforderung, bspw. Datenbank, zwei Klassenbibliotheken. Die eine enthält die Schnittstellen und die andere die Implementierungen. Dadurch lässt sich die Implementierung jeder Zeit austauschen, ohne den Programmcode anderer Module anzupassen. Die Klassen zu den Schnittstellen werden mittels CDI erzeugt (inject). Es gibt aber auch Klassen, deren Erzeugung nicht über CDI stattfinden soll, dafür verwende ich Fabriken, die mit Hilfe von CDI injiziert werden.

Beispiel: database-interface.jar und database-implementation.jar
Die Schnittstellen in database-interface.jar sind:

Product, ProductFactory, ProductFacade.

ProductFacade wird injiziert.
Product wird über die ProductFactory erzeugt, da es mehrere Implementierungen gäbe könnte (UserDefault, UserDefaultMock, UserClient, UserJPA usw...).
Die ProductFactory wird injeziert. Von ihr gibt es verschiedene Implementierungen einmal für UserDefaultFactory, UserMockFactory ... . Die Factory, die verwendet wird, besitzt kein @alternative (oder alternative Eintrag in beans.xml).

Die Erzeugung von Product kann auch mit CDI über InitialContext.lookup geschehen. Ich finde, dass es aber unschön ist.

Ist diese Vorgehensweise gut?

Die Erzeugung von Product kann auch mit CDI über InitialContext.lookup geschehen. Ich finde, dass es aber unschön ist.

Ist diese Vorgehensweise gut?


----------



## KSG9|sebastian (16. Jan 2013)

Hört sich für mich erstmal nach ziemlich vielen Abstraktionen an, die man nicht braucht?! Kommt natürlich auf den Anwendungsfall an, aber was ganz mies ist es, pauschal für jede Klasse ein Interface zu erzeugen. Am besten zuerst die Implementierung und dann "export interface/all methods", das braucht niemand.

Überleg dir, an welchen Stellen es WIRKLICH gewünscht ist, die Implementierung zu tauschen. Und überleg dir auch, anhand von schon laufenden Anwendungen, wie oft die Implementierung an einer gewissen Stelle ausgetauscht wurde und ob du wirklich Vorteile hattest, oder ob es ohne Interface genauso gegangen wäre.

Im Prinzip spricht aber nix gegen dein Vorgehen, aber du solltest trotzdem bei jedem Interface/jeder Implementierung prüfen, ob es wirklich benötigt wird. Wozu benötigst du eigentlich die Factories?

Du kannst doch auch zwei Implementierungen bauen (ich denke es geht um Test?!) und diese per @Qualifier/@Named bei deinen Tests injecten?

CDI macht im Hintergrund nichts anderes, als einen Lookup über den InitialContext auszulösen. Was gefällt dir daran nicht?

Gruß Sebastian

** edit **
Noch etwas zu Abstraktionen. Was ich schon soo oft gesehen habe war folgendes Konstrukt:

```
interface DataProvider {
}
interface DataConnector {
}

// Connector für Files
class FileConnector implements DataConnector {

}

// Connector für DB
class DBConnector implements DataConnector {

}

// für Zugriffe auf Daten in einer DB
class DatabaseDataProvider implements DataProvider{
   public DatabaseDataProvider(DataConnector connector) { ...}
}
// für Zugriffe auf Daten in einem File
class FileDataProvider implements DataProvider{
   public FileDataProvider(DataConnector connector) { .. }
}
```

In dem Beispiel gibt es zwei "Schichten". Einen Provider welcher Daten ermittelt und einen Connector, welcher dazu da ist, die Verbindung zu einer Resource aufzubauen.
Die findigen Entwickler dachten sich nun: Abstraktion ist etwas tolles, am besten auf jeder Ebene.
Durch dieses Konstrukt ist es nun aber möglich, einen DatabaseDataProvider mit einem FileConnector zu erzeugen, was absolut keinen Sinn macht. Die Abstraktion auf der Connector-Ebene ist an der Stelle erstmal unnötig, daher: *Überleg dir, welche Abstraktionen wirklich nötig sind*.

Nochmals an Inversion of Control denken: Der Client bestimmt die Schnittstelle/den Vertrag, nicht die Implementierung!


----------



## JavaEEDeveloper (16. Jan 2013)

Danke 

Ich möchte meine Enterprise-Application etwas verteilter entwickeln.Ein Server für die Datenbank (ejb mit Zugriff auf SQL-Server), Ein anderer für die Businesslogik und einer für das Web (Primefaces usw ...).



> Im Prinzip spricht aber nix gegen dein Vorgehen, aber du solltest trotzdem bei jedem Interface/jeder Implementierung prüfen, ob es wirklich benötigt wird. Wozu benötigst du eigentlich die Factories?
> 
> Du kannst doch auch zwei Implementierungen bauen (ich denke es geht um Test?!) und diese per @Qualifier/@Named bei deinen Tests injecten?



Wenn ich mehrere Objkte von Product benötige, dann muss ich ja 50 Instanzen injizieren. Dazu sind die Factories gedacht. Ich injiziere eine Factory des benötigten Typs und rufe dann 50 createProduct() auf. 
Product ist ein Entity auf dem Datenbankserver, aber auf dem Webserver soll nicht zu sehen sein, welche Annotationen verwendet wurden. Zudem wollte ich lazy-loading auf dem Webserver implementieren. Lazy-loading funktioniert leider nicht, wenn ich per jdni mir eine Entity vom Datenbankserver hole. Ich müsste die Entity einem EntityManager auf dem Webserver übergeben, der dann direkt auf den SQL-Server zugreift, das darf aber nicht sein (wegen cache + anderer Sicherheitsbereich).


----------

