Ich würde argumentieren, dass Sie zwei Prinzipien verletzen: das Prinzip der einheitlichen Verantwortung (Single Responsibility Principle, SRP) und das offene/geschlossene Prinzip (OCP).
Sie verstoßen gegen die SRP, da die Bootstrapping-Klasse mehr als einen Grund hat, geändert zu werden: wenn Sie die Modellbindung oder die Auto-Mapper-Konfiguration ändern.
Sie würden das OCP verletzen, wenn Sie zusätzlichen Bootstrapping-Code zum Konfigurieren einer anderen Unterkomponente des Systems hinzufügen würden.
Wie ich das normalerweise handhabe ist, dass ich die folgende Schnittstelle definiere.
public interface IGlobalConfiguration
{
void Configure();
}
Für jede Komponente im System, die Bootstrapping benötigt, würde ich eine Klasse erstellen, die diese Schnittstelle implementiert.
public class AutoMapperGlobalConfiguration : IGlobalConfiguration
{
private readonly IConfiguration configuration;
public AutoMapperGlobalConfiguration(IConfiguration configuration)
{
this.configuration = configuration;
}
public void Configure()
{
// Add AutoMapper configuration here.
}
}
public class ModelBindersGlobalConfiguration : IGlobalConfiguration
{
private readonly ModelBinderDictionary binders;
public ModelBindersGlobalConfiguration(ModelBinderDictionary binders)
{
this.binders = binders;
}
public void Configure()
{
// Add model binding configuration here.
}
}
Ich benutze Ninject, um die Abhängigkeiten zu injizieren.IConfiguration
ist die zugrunde liegende Implementierung der statischen AutoMapper
Klasse und ModelBinderDictionary
ist das ModelBinders.Binder
Objekt. Ich würde dann eine NinjectModule
definieren, die die angegebene Assembly für jede Klasse scannen würde, die die Schnittstelle IGlobalConfiguration
implementiert, und diese Klassen zu einem Verbund hinzufügen.
public class GlobalConfigurationModule : NinjectModule
{
private readonly Assembly assembly;
public GlobalConfigurationModule()
: this(Assembly.GetExecutingAssembly()) { }
public GlobalConfigurationModule(Assembly assembly)
{
this.assembly = assembly;
}
public override void Load()
{
GlobalConfigurationComposite composite =
new GlobalConfigurationComposite();
IEnumerable<Type> types =
assembly.GetExportedTypes().GetTypeOf<IGlobalConfiguration>()
.SkipAnyTypeOf<IComposite<IGlobalConfiguration>>();
foreach (var type in types)
{
IGlobalConfiguration configuration =
(IGlobalConfiguration)Kernel.Get(type);
composite.Add(configuration);
}
Bind<IGlobalConfiguration>().ToConstant(composite);
}
}
Ich würde dann den folgenden Code der Datei Global.asax hinzufügen.
public class MvcApplication : HttpApplication
{
public void Application_Start()
{
IKernel kernel = new StandardKernel(
new AutoMapperModule(),
new MvcModule(),
new GlobalConfigurationModule()
);
Kernel.Get<IGlobalConfiguration>().Configure();
}
}
Jetzt ist mein Bootstrapping-Code an SRP und OCP gebunden. Ich kann einfach zusätzlichen Bootstrapping-Code hinzufügen, indem ich eine Klasse erstelle, die die IGlobalConfiguration
-Schnittstelle implementiert, und meine globalen Konfigurationsklassen haben nur einen Grund, sich zu ändern.
weg und Sie müssen immer noch die Configure ändern Methode in AutoMapperGlobalConfiguration jedes Mal, wenn Sie ein neues Mapping hinzufügen müssen – Omu
Aber das würde OCP nicht verletzen. OCP ist nicht schreiben einmal nie wieder berühren. OCP gibt an, dass der Benutzer des Bootstrapping-Codes, das GlobalConfigurationModule (GCM), sich auf die Abstraktion und nicht auf die Implementierung der Conrete verlassen sollte. Wenn ich Bootstrapping für log4net hinzufügen würde, würde ich eine Klasse Log4NetGlobalConfiguration erstellen, die IGlobalConfiguration implementieren würde. Ich würde jedoch keinen anderen Teil meines Codes und definitiv nicht das GCM ändern müssen, da es keine komplizierten Kenntnisse über die konkrete Implementierung der IGlobalConfiguration-Schnittstelle besitzt. – mrydengren
Ich bin in Zweifel. Sobald Mapper.CreateMap <>() ausgeführt wurde, existieren die Karten bis zum Beenden der Anwendung? – JPCF