什么是静态方法inheritance的正确select?
我明白静态方法inheritance不支持在C#中。 我还读了一些讨论(包括这里),其中开发人员声称需要这个function,典型的回应是“如果你需要静态成员inheritance,你的devise存在缺陷”。
好吧,鉴于面向对象不希望我想到静态inheritance,我必须得出结论,我明显需要它指向我的devise中的一个错误。 但是,我卡住了。 我真的很感谢一些帮助解决这个问题。 这是挑战
我想创build一个抽象的基类(我们称之为Fruit),它封装了一些复杂的初始化代码。 这段代码不能放在构造函数中,因为它的一部分依赖于虚方法调用。
Fruit将被其他具体类(Apple,Orange)inheritance,每个类都必须公开一个标准工厂方法CreateInstance()来创build和初始化一个实例。
如果静态成员inheritance是可行的,我会将工厂方法放在基类中,并使用虚拟方法调用派生类来获取具体实例必须初始化的types。 客户端代码将简单调用Apple.CreateInstance()来获取完全初始化的Apple实例。
但显然这是不可能的,所以有人可以解释我的devise需要改变以适应相同的function。
一个想法:
public abstract class Fruit<T> where T : Fruit<T>, new() { public static T CreateInstance() { T newFruit = new T(); newFruit.Initialize(); // Calls Apple.Initialize return newFruit; } protected abstract void Initialize(); } public class Apple : Fruit<Apple> { protected override void Initialize() { ... } }
并像这样打电话:
Apple myAppleVar = Fruit<Apple>.CreateInstance();
不需要额外的工厂类。
将工厂方法移出该types,并将其放入自己的Factory类中。
public abstract class Fruit { protected Fruit() {} public abstract string Define(); } public class Apple : Fruit { public Apple() {} public override string Define() { return "Apple"; } } public class Orange : Fruit { public Orange() {} public override string Define() { return "Orange"; } } public static class FruitFactory<T> { public static T CreateFruit<T>() where T : Fruit, new() { return new T(); } }
但是,正如我所看到的,没有必要将Create方法移动到它自己的Factory类(尽pipe我认为它是可取的 – 关注分离),您可以将它放在Fruit类中:
public abstract class Fruit { public abstract string Define(); public static T CreateFruit<T>() where T : Fruit, new() { return new T(); } }
而且,看看它是否有效:
class Program { static void Main( string[] args ) { Console.WriteLine (Fruit.CreateFruit<Apple> ().Define ()); Console.WriteLine (Fruit.CreateFruit<Orange> ().Define ()); Console.ReadLine (); } }
为什么不用create方法创build一个工厂类(模板化)?
FruitFactory<Banana>.Create();
我会做这样的事情
public abstract class Fruit() { public abstract void Initialize(); } public class Apple() : Fruit { public override void Initialize() { } } public class FruitFactory<T> where T : Fruit, new { public static <T> CreateInstance<T>() { T fruit = new T(); fruit.Initialize(); return fruit; } } var fruit = FruitFactory<Apple>.CreateInstance()
.NET BCL中的WebRequest
类及其派生types代表了这种devise如何实现得比较好的一个很好的例子。
WebRequest
类有几个子类,包括HttpWebRequest
和FtpWebReuest
。 现在,这个WebRequest
基类也是一个工厂types,并且公开了一个静态的Create
方法(实例构造函数被工厂模式需要隐藏)。
public static WebRequest Create(string requestUriString) public static WebRequest Create(Uri requestUri)
此Create
方法返回WebRequest
类的特定实现,并使用URI(或URIstring)来确定要创build和返回的对象的types。
这具有以下使用模式的最终结果:
var httpRequest = (HttpWebRequest)WebRequest.Create("http://stackoverflow.com/"); // or equivalently var httpRequest = (HttpWebRequest)HttpWebWebRequest.Create("http://stackoverflow.com/"); var ftpRequest = (FtpWebRequest)WebRequest.Create("ftp://stackoverflow.com/"); // or equivalently var ftpRequest = (FtpWebRequest)FtpWebWebRequest.Create("ftp://stackoverflow.com/");
我个人认为这是解决这个问题的一个好方法,它似乎确实是.NET Framework创build者的优先方法。
首先,没有可以是虚拟的静态初始化并不意味着你不能有“标准”的成员方法,可能会超载。 其次,你可以从构造函数中调用你的虚拟方法,它们将按预期工作,所以这里没有问题。 第三,你可以使用generics有types安全的工厂。
下面是一些代码,它使用由构造函数调用的factory +成员的Initialize()方法(并且它是受保护的,所以您不必担心在创build对象后有人会再次调用它):
abstract class Fruit { public Fruit() { Initialize(); } protected virtual void Initialize() { Console.WriteLine("Fruit.Initialize"); } } class Apple : Fruit { public Apple() : base() { } protected override void Initialize() { base.Initialize(); Console.WriteLine("Apple.Initialize"); } public override string ToString() { return "Apple"; } } class Orange : Fruit { public Orange() : base() { } protected override void Initialize() { base.Initialize(); Console.WriteLine("Orange.Initialize"); } public override string ToString() { return "Orange"; } } class FruitFactory { public static T CreateFruit<T>() where T : Fruit, new() { return new T(); } } public class Program { static void Main() { Apple apple = FruitFactory.CreateFruit<Apple>(); Console.WriteLine(apple.ToString()); Orange orange = new Orange(); Console.WriteLine(orange.ToString()); Fruit appleFruit = FruitFactory.CreateFruit<Apple>(); Console.WriteLine(appleFruit.ToString()); } }
我会说最好的办法是在水果类上创build一个虚拟/抽象的Initialise方法,然后创build一个外部的“水果工厂”类来创build实例:
public class Fruit { //other members... public abstract void Initialise(); } public class FruitFactory() { public Fruit CreateInstance() { Fruit f = //decide which fruit to create f.Initialise(); return f; } }