Dies ist ein bisschen eine Design-Frage mit inneren Klassen in Java (Java 8). Der gesamte Beispielcode ist unterhalb meines TextesJava: Innere Klassen, die auf die privaten Variablen des jeweils anderen zugreifen - eine gute Methode zum Kapseln externer APIs?
Als Beispiel, habe ich einige Maschinen, die das Pumpen von Kraftstoff aus einem Öl-Geysir zu einer Art von Brenner, die ich mit einer externen API namens OilAPI steuern kann.
Ich habe eine Controller-Klasse, die die Arbeit macht und entscheidet, welcher Brenner Öl von welchem Geysir bekommen muss, aber ich möchte nicht, dass die API Klassen wie Geyser und Burner in den Controller laufen (auch da die API noch einige Änderungen im Laufe der Zeit erfährt).
Jetzt, um es zu verkapseln, so erstelle ich eine Klasse namens FuelFacility, die die gesamte Logik der OilAPI enthält.
Die Sache ist, ich habe die Klassen Pumpe und Motor als innere Klassen in FuelFacility gesetzt.
Zunächst ist dies für die Syntax von Pump.activate() anstelle von FuelFacility.activatePump (...) oder was auch immer gehen.
Weiter ist, dass, um einen Geyser und Brenner in der Oil API zu verbinden, Sie sowohl die Geyser und Brenner Objekte benötigen, aber ich möchte sie nicht extern aussetzen, also um eine Art "Connect Pumpe und Motor "muss ich entweder der Pumpe erlauben, auf die Variable Brenner des Motors zuzugreifen, der Engine, um auf die Variable Geyser + der Pumpe zuzugreifen, oder der FuelFacility, um auf diese beiden Variablen zuzugreifen. Im folgenden Beispiel habe ich eine Engine.connectToPump (pump) -Methode, die im Grunde genommen in meinem tatsächlichen Code funktioniert.
Meine Teamkollegen dachten, dass dies ein bisschen seltsam ist; sie sagten, dass der Zugriff auf die privaten Variablen über die Klassen die Kapselung unterbricht, und insbesondere, dass ein Programmierer, der den Code von "außerhalb" betrachtet (dh vom Standpunkt der Arbeit in der Controller-Klasse), davon ausgehen würde, dass er einmal erhalten hat Die Engine- und Pump-Objekte wären nicht mehr abhängig von zB welches OilAPI-Objekt das ursprüngliche FuelFacility verwendet (obwohl dies wie im Folgenden beschrieben endgültig sein sollte) oder aufeinander.
Nun, seitdem habe ich es geschafft, ihre Meinung ein wenig zu ändern - das ist im Grunde nur eine Art Dinge zu tun, an die sie nicht gewöhnt sind, aber das ist keine schlechte Übung.
Aber jetzt bin ich damit beschäftigt, einige andere Codes zu ändern, um auf eine ähnliche Art und Weise zu arbeiten, und ich möchte nur sicherstellen, bevor ich fortfahre, was mache ich gute Praxis? Gibt es einen besseren Weg, Dinge zu tun? Beratung ist erwünscht!
Code:
Oil API (nicht unter meiner Kontrolle):
public class OilAPI {
private final Pipes pipes = new Pipes();
public static class Geyser {}
public static class Burner {}
public static class Pipes {
public void createConnectionBetweenGeyserAndBurner(Geyser g, Burner b) {
// Connects geyser and burner
}
}
public Geyser getGeyserWithId(String id) {
// Actually retrieves a specific instance
return new Geyser();
}
public Burner getBurnerWithId(String id) {
// Actually retrieves a specific instance
return new Burner();
}
public void activateGeyser(Geyser g) {
// do stuff
}
public void activateBurner(Burner b) {
// do stuff
}
public void createConnectionBetweenGeyserAndBurner(Geyser g, Burner b) {
pipes.createConnectionBetweenGeyserAndBurner(g,b);
}
}
Kraftstoff Einrichtung (Klasse I das Öl API verkapseln erstellt):
public class FuelFacility {
private final OilAPI oil;
FuelFacility(OilAPI oil) {
this.oil = oil;
}
public Pump getPumpForId(String id) {
OilAPI.Geyser geyser = oil.getGeyserWithId(id);
return new Pump(geyser);
}
public Engine getEngineForId(String id) {
OilAPI.Burner burner = oil.getBurnerWithId(id);
return new Engine(burner);
}
public class Pump {
private final OilAPI.Geyser geyser;
private Pump(OilAPI.Geyser geyser) {
this.geyser = geyser;
}
public void activate() {
oil.activateGeyser(geyser);
}
}
public class Engine {
private final OilAPI.Burner burner;
private Engine(OilAPI.Burner burner) {
this.burner = burner;
}
public void connectToPump(Pump pump) {
oil.createConnectionBetweenGeyserAndBurner(pump.geyser, burner);
}
public void activate() {
oil.activateBurner(burner);
}
}
}
Steuerung (von mir Besitz und sitzt innerhalb unserer Code-Basis):
public class Controller {
public static void main(String[] args) {
// We actually get these from a database
String engineId = "engineId";
String pumpId = "pumpId";
OilAPI oil = new OilAPI();
FuelFacility facility = new FuelFacility(oil);
FuelFacility.Engine engine = facility.getEngineForId(engineId);
FuelFacility.Pump pump = facility.getPumpForId(pumpId);
engine.connectToPump(pump);
}
}
Danke für die Antwort! "In diesem Design sind FuelFacility, Pump und Engine so nah an OilAPI, Geyser und Burner, dass ich nicht sicher bin, ob Sie Controller tatsächlich so gut schützen." Ja, das ist nur in diesem Beispiel, in der Praxis sind sie ein bisschen anders. Aber die Art von Dingen, für die ich mich einsetzte, war zum Teil eine Anti-Korruptionsschicht: http://www.markhneedham.com/blog/2009/07/07/domain-driven-design-anti-corruption- layer/ https://softwareengineering.stackexchange.com/questions/184464/what-is-an-anti-corruption-layer-and-how-is-it-used –