C# 有没有更好的方法来伪造静态类接口?
这种设计模式有意义吗?我最初有一个静态类,它为每个实现的算法返回一个C# 有没有更好的方法来伪造静态类接口?,c#,design-patterns,factory-pattern,C#,Design Patterns,Factory Pattern,这种设计模式有意义吗?我最初有一个静态类,它为每个实现的算法返回一个HashFunction public delegate int HashFunction(int seed, params int[] keys); 但后来我意识到我需要几个元数据以及每个算法,所以我创建了这个接口: public interface IHashAlgorithm { HashFunction CalculateHash { get; } NoiseFunction CalculateNois
HashFunction
public delegate int HashFunction(int seed, params int[] keys);
但后来我意识到我需要几个元数据以及每个算法,所以我创建了这个接口:
public interface IHashAlgorithm
{
HashFunction CalculateHash { get; }
NoiseFunction CalculateNoise { get; }
int Maximum { get; }
int Minimum { get; }
}
public delegate double NoiseFunction(int seed, params int[] keys);
internal sealed class HashAlgorithm : IHashAlgorithm
{
public HashAlgorithm(HashFunction function, int min, int max)
{
CalculateHash = function;
Minimum = min;
Maximum = max;
}
public HashFunction CalculateHash { get; private set; }
public NoiseFunction CalculateNoise
{
get { return Noise; }
}
public int Maximum { get; private set; }
public int Minimum { get; private set; }
private double Noise(int seed, params int[] keys)
{
return ((double)CalculateHash(seed, keys) - Minimum)/
((double)Maximum - Minimum + 1);
}
}
内部类实现所需的接口:
public interface IHashAlgorithm
{
HashFunction CalculateHash { get; }
NoiseFunction CalculateNoise { get; }
int Maximum { get; }
int Minimum { get; }
}
public delegate double NoiseFunction(int seed, params int[] keys);
internal sealed class HashAlgorithm : IHashAlgorithm
{
public HashAlgorithm(HashFunction function, int min, int max)
{
CalculateHash = function;
Minimum = min;
Maximum = max;
}
public HashFunction CalculateHash { get; private set; }
public NoiseFunction CalculateNoise
{
get { return Noise; }
}
public int Maximum { get; private set; }
public int Minimum { get; private set; }
private double Noise(int seed, params int[] keys)
{
return ((double)CalculateHash(seed, keys) - Minimum)/
((double)Maximum - Minimum + 1);
}
}
在某种公共静态工厂类中创建并返回:
public static class Hashing
{
private static readonly IHashAlgorithm MurmurHash2Instance =
new HashAlgorithm(MurmurHash2Hash, 0, int.MaxValue);
private static readonly IHashAlgorithm ReSharperInstance =
new HashAlgorithm(ReSharperHash, int.MinValue, int.MaxValue);
public static IHashAlgorithm MurmurHash2
{
get { return MurmurHash2Instance; }
}
public static IHashAlgorithm ReSharper
{
get { return ReSharperInstance; }
}
private static int MurmurHash2Hash(int seed, params int[] keys)
{
//...
}
private static int ReSharperHash(int seed, params int[] keys)
{
//...
}
}
我更希望能够在每个算法的静态类上实现IHashAlgorithm
:
public static class MurmurHash2 : IHashAlgorithm
{
public static int Hash(int seed, params int[] keys) {...}
//...
}
不幸的是,C#不允许这样做,所以这是我试图绕过它的方法。没有办法伪造静态类接口,很多时候,当我认为我需要一个静态类接口时,我实际上需要常用的实例接口。你不能在C#中传递一个静态类的“实例”,也没有办法给一个函数一个“静态”接口,甚至一个静态“类”来使用它的静态方法。当您调用静态方法时,它总是显式的,并且您将方法“硬链接”到您调用的静态类,这不是一件好事 基于静态方法的可变性很难进行单元测试。依赖于这种可变性的类灵活性较差。想象一下,如果某个函数会显式地使用静态类中的某个算法。这样的函数会显式地将自身耦合到特定的算法
public class SomeBusinessLogic
{
public Result HandleDocument(IDocument doc)
{
// some transformations...
int hash = Hashing.ReSharperHash.CalculateHash(seed, doc.Properties);
// some other code ...
}
}
public class SomeBusinessLogic
{
// injection in constructor
public SomeBusinessLogic(IHashingAlgorithm hashing)
{
// put hashing in a field of the class
}
// OR injection in method itself, if hashing is only used in this method
public Result HandleDocument(IDocument doc, IHashingAlgorithm hashing)
{
// some transformations...
int hash = hashing.CalculateHash(seed, doc.Properties);
// some other code ...
}
}
那有什么不对吗
HandleDocument
函数时,它可能会意外失败public class SomeBusinessLogic
{
public Result HandleDocument(IDocument doc)
{
// some transformations...
int hash = Hashing.ReSharperHash.CalculateHash(seed, doc.Properties);
// some other code ...
}
}
public class SomeBusinessLogic
{
// injection in constructor
public SomeBusinessLogic(IHashingAlgorithm hashing)
{
// put hashing in a field of the class
}
// OR injection in method itself, if hashing is only used in this method
public Result HandleDocument(IDocument doc, IHashingAlgorithm hashing)
{
// some transformations...
int hash = hashing.CalculateHash(seed, doc.Properties);
// some other code ...
}
}
有什么更好的办法?提取一个抽象哈希函数的接口,并在需要进行哈希时显式地请求它。因此,只要算法是无状态的,您仍然可以将其实现为某种类型的单例,但是客户机代码将与哈希细节没有任何耦合。谁知道呢,也许有一天你会发现你需要一些参数化的散列算法,你可以在每次需要的时候创建一个新的算法实例
我正在使用您的界面,但风格有所改变:
public interface IHashAlgorithm
{
int CalculateHash(int seed, params int[] keys);
int CalculateNoise(int seed, params int[] keys);
int Maximum { get; }
int Minimum { get; }
}
public static class StatelessHashAlgorithms
{
private static readonly IHashAlgorithm MurmurHash2Instance =
new HashAlgorithm(MurmurHash2Hash, 0, int.MaxValue);
private static readonly IHashAlgorithm ReSharperInstance =
new HashAlgorithm(ReSharperHash, int.MinValue, int.MaxValue);
public static IHashAlgorithm MurmurHash2
{
get { return MurmurHash2Instance; }
}
public static IHashAlgorithm ReSharper
{
get { return ReSharperInstance; }
}
private static int MurmurHash2Hash(int seed, params int[] keys)
{
//...
}
private static int ReSharperHash(int seed, params int[] keys)
{
//...
}
}
public class SomeCustomHashing : IHashAlgorithm
{
public SomeCustomHashing(parameters)
{
//parameters define how hashing behaves
}
// ... implement IHashAlgorithm here
}
所有客户端代码都应该在需要哈希接口时显式地请求哈希接口,这称为依赖项注入,可以在类级别或方法级别上完成。然后,类的调用方或创建者将负责提供哈希算法
public class SomeBusinessLogic
{
public Result HandleDocument(IDocument doc)
{
// some transformations...
int hash = Hashing.ReSharperHash.CalculateHash(seed, doc.Properties);
// some other code ...
}
}
public class SomeBusinessLogic
{
// injection in constructor
public SomeBusinessLogic(IHashingAlgorithm hashing)
{
// put hashing in a field of the class
}
// OR injection in method itself, if hashing is only used in this method
public Result HandleDocument(IDocument doc, IHashingAlgorithm hashing)
{
// some transformations...
int hash = hashing.CalculateHash(seed, doc.Properties);
// some other code ...
}
}
它解决了上述问题:
另外,还有一个方面是“你的领域是什么”。如果您正在编写一些业务应用程序,并且到处调用static
Math.Sqrt(…)
,这很好,因为没有其他行为。但是,如果您正在编写一些数学库,并且您有几个不同的平方根实现,具有不同的算法或精度,您可能希望将它们包装到一个接口中,并作为接口实例传递,以便能够扩展。如果您需要模拟“静态接口”,我认为您应该使用make singleton,这看起来很像你正在做的事情,但奇怪的是,Ingenu是对的——单身是唯一的方法。当然,如果希望严格控制API,可以选择显式接口实现。