Ist eine "Master Preferences" -Klasse eine gute Idee?

8

Ich habe eine Klasse, die Benutzereinstellungen für ein großes Softwareprojekt verwaltet. Jede Klasse im Projekt, die möglicherweise eine Benutzereinstellung aus einem persistenten Speicher ablegen oder abrufen muss, ruft die statischen Methoden für diese Klasse auf. Durch diese zentralisierte Verwaltung können die Voreinstellungen vollständig programmgesteuert gelöscht werden. Dies wäre unmöglich, wenn jede Voreinstellung nahe an ihrem Verwendungscode behandelt würde, der während des gesamten Projekts verstreut ist.

Ich bin dabei auf eine andere Implikation des Zentralisierungsdesigns gestoßen. Die Software hat eine öffentliche API. Diese API kann selbst in einem Jar bereitgestellt werden. Klassen in dieser API beziehen sich möglicherweise auf die Pref-Verwaltungsklasse. Der Pref-Manager muss also in das API-Jar gehen.

Jede Einstellung kann einen Standardwert haben. Nach dem Start der Software wird dieser Standardwert möglicherweise berechnet. Der Algorithmus hängt von der Präferenz ab und neigt daher dazu, sich in der Nähe des Verwendungscodes zu befinden. Wenn also der Pref Manager eine Standardvorgabe hat, ruft er die fragliche Klasse auf.

Aber jetzt ist dieser Pref-Manager zu einer "Octopus-Klasse" geworden, die alle möglichen Klassen in das API-Jar hineinsaugt, das nicht dort sein sollte. Wenn dies nicht der Fall ist, führen Programme, die das API-Jar verwenden, schnell zu ClassDef-Exceptions. Wenn dies der Fall ist, ist das API-Jar jetzt aufgebläht, da sich jede dieser anderen Klassen auf andere beziehen kann.

Im Allgemeinen verwalten andere Java-Programmierer ihre Präferenzen mit einer zentralisierten Klasse?

Ist es sinnvoll, diese statische Pref-Management-Klasse als Teil einer öffentlichen API zu verteilen?

Soll dieser Pref-Manager der Code für die Festlegung von Standardeinstellungen sein?

    
Paul Brinkley 26.02.2009, 23:34
quelle

6 Antworten

11

Ich glaube, die Antwort auf Ihre erste Frage lautet "Ja" und "Nein".

Einstellungen werden häufig als eine zentralisierte Klasse behandelt, in dem Sinne, dass die Klasse für viele Klassen im Projekt eine "Senke" ist. Wenn Sie versuchen, es näher an den aufrufenden Code zu bringen, bedeutet dies, dass Sie Probleme haben, wenn die gleiche Präferenz später an anderer Stelle nützlich ist. Meiner Erfahrung nach führt auch der Versuch, die Präferenzen "zu nah" zu setzen, zu einer sehr uneinheitlichen Handhabung.

Davon abgesehen ist es oft vorzuziehen, mehrere Präferenzklassen oder "Präferenzsätze" zu verwenden, die jeweils ein Modul oder Submodul unterstützen. Wenn Sie sich die Hauptkomponenten Ihrer Architektur ansehen, werden Sie oft feststellen, dass die Menge der Präferenzen logisch partitioniert werden kann. Dies reduziert das Durcheinander in jeder Präferenzklasse. Noch wichtiger ist, dass Sie Ihr Programm in Zukunft in mehrere Gläser aufteilen können. Nun können die "Default-Wert" -Kalkulatoren in dem Modul platziert werden, aber immer noch in einem Bereich, der global genug ist.

Ich würde auch vorschlagen, Präferenzen nicht direkt als statische Methoden zu setzen, sondern eine getInstance () ähnliche Operation zu verwenden, um eine gemeinsam genutzte Instanz der Voreinstellungen zu erhalten und dann darauf zu operieren. Abhängig von Ihrer Semantik möchten Sie dieses Objekt möglicherweise für eine Weile sperren (z. B. wenn der Benutzer Einstellungen in einer Benutzeroberfläche bearbeitet) und dies ist einfacher, wenn Sie ein tatsächliches Objekt haben.

Für Ihre anderen Fragen würde ich sagen, dass Ihre öffentliche API eine Möglichkeit haben sollte, Benutzer die Präferenzen ändern zu lassen, aber nur, wenn Sie gut dokumentieren können, was die Ergebnisse dieser Änderungen sein könnten.

Wenn Sie eine einzelne API-Funktion verwenden, um den "Referenzmanager" zu erhalten, können Sie Benutzern die Möglichkeit geben, einen eigenen "Standardwertrechner" anzugeben. Der Präferenzmanager wird diesen Taschenrechner zuerst fragen, bevor er auf den von Ihnen standardmäßig bereitgestellten zurückgreift.

    
Uri 26.02.2009, 23:43
quelle
4

Können Sie Ihre Präferenzen nicht wirklich allgemein behandeln? Sie würden dann nur den Einstellungsmanager verwenden, um die Persistenz zu behandeln. Also von einer Klasse würden Sie nur zum Preference Manager PreferenceManager.setPreference (Schlüssel, Wert) sagen und es ist egal, was es in Bezug auf die Semantik der Daten spart.

Oder vereinfache ich das zu sehr?

    
Robin Barnes 26.02.2009 23:51
quelle
2

Ich bin kein Java Dev, aber soweit die ganze "Octopus Class" Sache geht, können Sie nicht nur eine Schnittstelle zum jar bereitstellen und die Aufrufe zwischen der Schnittstelle und dem prefs manager zur Laufzeit über die Anwendung verbinden Konfigurationsdatei, um den Prefs Manager zum Instanziieren zu bestimmen?

Etwas wie das .NET-Provider-Muster?

Auf diese Weise können Sie Ihr Jar vom Prefs-Manager entkoppeln.

    
rism 27.02.2009 00:07
quelle
1

Sie können sich Cocoas NSUserDefaults -Klasse als Inspiration ansehen. Es behandelt das Problem, das Sie beschreiben, indem Sie mehrere Ebenen von Voreinstellungen, Domänen genannt, haben. Wenn Sie den Wert für einen Schlüssel wie "PrintUsingAllCaps" suchen, sucht es zuerst nach einem Wert in der lokalen Domäne des Benutzers. Wenn es dort nicht gefunden wird, kann es die systemweite Domäne oder eine Domäne auf Netzwerkebene usw. überprüfen.

Der absolut letzte Ort, den es überprüft, heißt "Registration Domain", was im Grunde die hartcodierten Standardwerte sein soll. So kann ich zu jedem Zeitpunkt in meinem Code eine Präferenz in die Registrierungsdomäne schreiben, und NSUserDefaults liefert diesen Wert nur, wenn der Benutzer ihn nicht überschrieben hat.

In Ihrem Fall könnten Sie also eine Methode für Klassen bereitstellen, um einen Standardwert für einen Schlüssel festzulegen, bevor er auf den (möglicherweise) benutzerdefinierten Wert zugreift. Die Voreinstellungsklasse muss nichts über die Klassen wissen, die sie bedient.

Wie jemand anderes vorgeschlagen hat, könnten Sie, wenn Sie etwas Komplizierteres benötigen, ein DefaultValueProvider Callback-Objekt anstelle eines geraden Wertes setzen.

    
benzado 27.02.2009 00:03
quelle
0

Ich habe meine erste Antwort gelöscht, da ich missverstanden habe, was der Autor gefragt hat.

Um die eigentliche Frage tatsächlich anzusprechen - es fühlt sich an, als ob Ihr Wunsch, Präferenzen (und die Berechnung der Standardwerte) mit dem Code zu versehen, der sie verwendet, sinnvoll ist.

Könnten Sie beide Anforderungen erfüllen, indem Sie für jeden Bereich, der einem Muster für diesen Bereich folgt, eine Voreinstellungscontainerklasse verwenden, diese aber mit einer "globalen" Einstellungsobjektkollektion registrieren?

Ihre globale Sammlung könnte Dinge wie Iterieren über jeden Satz von Voreinstellungen und setzen Sie sie auf Standardeinstellungen zurück, aber Ihre Vorlieben selbst würden immer noch lokal definiert und gepflegt werden, so dass es nicht in andere Teile des Codes spinnt.

>

Das einzige Problem, das ich sehen kann, ist, dass Sie, wenn Sie zulassen, dass das Einstellungsobjekt sich selbst registriert, wenn es instanziiert wird, das Risiko einzugehen versucht, mit einigen der Einstellungen, die noch nicht instanziiert wurden, auf Standardwerte zurückzusetzen.

Ich nehme an, dass dies behoben werden könnte, indem die Hauptklasse "preference" alle anderen Instanzen instanziiert, dann könnte jedes Stück Code sein lokales Präferenzobjekt von der zentralen Instanz abrufen, obwohl es ein statischer Getter ist.

Dies scheint sehr ähnlich zu sein wie einige Logger funktionieren. Es gibt einen zentralen Mechanismus für die Verwaltung von Protokollierungsstufen, Ausgabeströmen und dergleichen, aber jede Klasse hat ihre eigene Instanz einer "Protokoll" -Methode und protokolliert sie.

Ich hoffe, das war mehr im Plan. Oh, ich stimme auch der akzeptierten Antwort zu, mach niemals alle deine Methoden öffentlich statisch, benutze immer einen Getter - du wirst froh sein, dass du es eines Tages getan hast.

    
Bill K 02.03.2009 17:32
quelle
0

Die JSR-10-API ( java.util.prefs.* ) verwendet eine Factory-Methode mit einem Class<?> -Parameter zum Erstellen von Preferences -Instanzen. Auf diese Weise kann die API Einstellungen aus verschiedenen Klassen desselben Pakets in einer einzigen Datei speichern.

    
martijno 05.02.2010 15:52
quelle

Tags und Links