lys*_*cid 8 .net c# oop refactoring
我正在开发基于.NET的应用程序,其中一些核心应用程序类仅使用静态方法设计.
用法示例:
// static access.
Parameters.GetValue("DefaultTimeout");
// static access.
Logger.Log("This is an important message!");
Run Code Online (Sandbox Code Playgroud)
已经存在使用这些静态方法的代码,因此无法更改此"接口".
这些类目前没有实现接口.我希望能够将这些类的实际实现与其接口分开.
这种重构的原因是这些对象将跨AppDomain边界使用.我希望能够注入一个"代理"对象,在非主应用程序域上将调用其他实现而不是默认实现.
总之,我的问题是:
如何轻松地使用基于接口的设计的静态访问来转换对象,以便在需要时可以替换它们的实现(但保持静态访问).
一旦重构,应该如何/ WHEN实际注入非默认实现?
Ada*_*rth 11
免责声明:以下建议基于不改变主叫方的重要性.我不是说这是最好的选择,只是我认为它是合适的.
无法在静态成员上使用接口,因此如果您不想更改调用代码,则可能必须保留静态.也就是说,你可以简单地让你的静态类包装一个接口,所以静态类本身没有任何实现 - 它将所有调用委托给接口.
这意味着您可以保留静态类和任何调用它的代码.这就像将静态类视为接口(或契约),但让它在内部根据情况交换实现.
这也意味着你的接口可以拥有与静态类不同的签名,因为接口不必符合调用代码的期望 - 基本上,它会将你的静态类变成一种桥.
简而言之:使用静态构造函数来解决此接口的给定实现.
静态通常是每个AppDomain(除非按照ThreadStaticAttribute,然后按AppDomain /线程进行修饰),这样您就可以根据当前的AppDomain确定您所在的位置和所需的实现(每当静态首次在AppDomain中使用时,都会调用静态构造函数) .这意味着一旦构造,该特定静态类的包装实现将在AppDomain的持续时间内保留(尽管您可以实现刷新实现的方法).
负责此操作的代码可以在静态类中,也可以将其中一个接口实现简单地作为AppDomain类型的代理管理器.任何类型的跨AppDomain调用都需要继承MarshalByRefObject.
http://msdn.microsoft.com/en-us/library/ms173139.aspx
另一个AppDomain中的Type的CreateInstance
样品申请
您应该只能将其复制并粘贴到新的控制台应用程序中.这样做是为默认AppDomain注册一个实现,为用户自己创建的AppDomain注册一个实现.默认只是创建接口的远程实现(在另一个AppDomain中).为了演示"静态每AppDomain"的想法,远程实现委托另一个非默认域的实现.
您可以动态更改实现,您需要更改的是静态类构造函数(以决定要选择的实现).请注意,Main在这种情况下,您无需更改方法,即我们的调用代码.
using System;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine(Parameters.GetValue(""));
Console.Read();
}
}
static class Parameters
{
private static IParameterProvider _provider;
static Parameters()
{
if (AppDomain.CurrentDomain.IsDefaultAppDomain())
{
_provider = new ParameterProviderProxy(AppDomain.CreateDomain(Guid.NewGuid().ToString()));
}
else
{
// Breakpoint here to see the non-default AppDomain pick an implementation.
_provider = new NonDefaultParameterProvider();
}
}
public static object GetValue(string name)
{
return _provider.GetValue(name);
}
}
interface IParameterProvider
{
object GetValue(string name);
}
class CrossDomainParameterProvider : MarshalByRefObject, IParameterProvider
{
public object GetValue(string name)
{
return Parameters.GetValue(name);
}
}
class NonDefaultParameterProvider : IParameterProvider
{
public object GetValue(string name)
{
return AppDomain.CurrentDomain.FriendlyName;
}
}
class ParameterProviderProxy : IParameterProvider
{
private IParameterProvider _remoteProvider;
public ParameterProviderProxy(AppDomain containingDomain)
{
_remoteProvider = (CrossDomainParameterProvider)containingDomain.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName,
typeof(CrossDomainParameterProvider).FullName);
}
public object GetValue(string name)
{
return _remoteProvider.GetValue(name);
}
}
Run Code Online (Sandbox Code Playgroud)
关于生命跨度的一个注记
管理静态类重构的主要问题之一通常不是客户端代码的更改(因为这有很多重构工具支持,并且有安全地完成它的技术),但是管理它的生命周期宾语.实例对象依赖于生命引用(否则它们是垃圾收集的),这些通常可以通过将其中的一个保存在某个公共静态成员中来"轻松访问",但通常这是您试图通过首先重构来避免的.
看起来您不必担心这种担忧,因为您将调用代码附加到静态类,因此寿命将保持不变.
对于每个静态方法,创建一个实例.添加一个可以为其分配任何实现的静态单例变量.使静态方法调用静态单例上的实例方法.
这将允许您在运行时交换实现,但您只能同时挂钩一个实现.
现有代码不需要更改.