我知道C#不支持静态方法继承。我还阅读了许多讨论(包括此处),其中开发人员声称需要此功能,典型的响应是“如果您需要静态成员继承,那么您的设计就存在缺陷”。
好的,鉴于OOP不希望我甚至想到静态继承,我必须得出结论,我对它的明显需求指出了我的设计中的错误。但是,我被困住了。我真的很感激帮助解决这个问题。这是挑战......
我想创建一个抽象基类(我们称之为Fruit),它封装了一些复杂的初始化代码。此代码不能放在构造函数中,因为其中一些代码将依赖于虚方法调用。
Fruit将由其他具体类(Apple,Orange)继承,每个类必须公开标准工厂方法CreateInstance()以创建和初始化实例。
如果静态成员继承是可行的,我会将工厂方法放在基类中,并使用对派生类的虚方法调用来获取必须从中初始化具体实例的类型。客户端代码可以简单地调用Apple.CreateInstance()来获取完全初始化的Apple实例。
但显然这是不可能的,所以有人可以解释我的设计需要如何改变以适应相同的功能。
答案 0 :(得分:57)
一个想法:
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();
不需要额外的工厂类。
答案 1 :(得分:16)
将工厂方法移出类型,并将其放在自己的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类(虽然我认为它是可取的 - 关注点分离 - ),你可以把它放在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 ();
}
}
答案 2 :(得分:4)
为什么不使用create方法创建工厂类(模板化)?
FruitFactory<Banana>.Create();
答案 3 :(得分:4)
我会做这样的事情
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()
答案 4 :(得分:3)
.NET BCL中的WebRequest
类及其衍生类型代表了如何相对较好地实现此类设计的一个很好的例子。
WebRequest
类有几个子类,包括HttpWebRequest
和FtpWebReuest
。现在,这个WebRequest
基类也是一个工厂类型,并公开了一个静态Create
方法(根据工厂模式的要求隐藏了实例构造函数)。
public static WebRequest Create(string requestUriString)
public static WebRequest Create(Uri requestUri)
此Create
方法返回WebRequest
类的特定实现,并使用URI(或URI字符串)来确定要创建和返回的对象的类型。
这具有以下使用模式的最终结果:
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创建者的优先方法。
答案 5 :(得分:3)
首先,没有可以是虚拟的静态初始化程序并不意味着你不能拥有可能被重载的“标准”成员方法。其次,您可以从构造函数中调用虚拟方法,它们将按预期工作,因此这里没有问题。第三,你可以使用仿制药来安装类型安全的工厂 这里有一些代码,它使用由构造函数调用的工厂+成员Initialize()方法(并且它受到保护,因此您不必担心,有人会在创建对象后再次调用它):
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());
}
}
答案 6 :(得分:0)
我想说最好的办法就是在fruit类上创建一个虚拟/抽象的Initialise方法,然后创建一个外部'fruit factory'类来创建实例:
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;
}
}