Если Ваша функция возвращает значение через ссылку, компилятор не может сохранить его в регистре при вызывании других функций, потому что, теоретически, первая функция может сохранить адрес переменной, переданной ему в глобально доступной переменной, и вызванные функции любого subsecuently могут изменить его, таким образом, компилятор будет иметь (1) сохраняют значение от регистров назад к памяти прежде, чем вызвать другие функции и (2) перечитает его, когда это будет необходимо от памяти снова после любого из таких вызовов.
, Если Вы возвращаетесь ссылкой, оптимизация Вашей программы пострадает
Одна идея:
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();
Никаких дополнительных фабричных классов не требуется.
Почему бы не создать класс фабрики (шаблонный) с помощью метода создания?
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()
Класс WebRequest
и его производные типы в .NET BCL представляют собой хороший пример того, как такого рода дизайн может быть относительно хорошо реализован.
] Класс WebRequest
имеет несколько подклассов, включая HttpWebRequest
и FtpWebReuest
. Теперь этот базовый класс WebRequest
также является фабричным типом и предоставляет статический метод Create
(конструкторы экземпляров скрыты, как того требует фабричный шаблон).
public static WebRequest Create(string requestUriString)
public static WebRequest Create(Uri requestUri)
This Метод 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/");
Лично я считаю, что это хороший способ решить проблему,
Прежде всего, отсутствие статических инициализаторов, которые могут быть виртуальными, не означает, что у вас не может быть «стандартных» методов-членов, которые могут быть перегружены. Во-вторых, вы можете вызывать свои виртуальные методы из конструкторов, и они будут работать должным образом, так что здесь нет никаких проблем. В-третьих, вы можете использовать дженерики для создания типобезопасной фабрики.
Вот код, который использует метод factory + member 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());
}
}
Я бы сказал, что лучше всего создать виртуальный / абстрактный метод инициализации для класса фруктов, который необходимо вызвать, а затем создать внешний класс «фабрика фруктов» для создания экземпляров:
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;
}
}
Move the factory method out of the type, and put it in its own Factory class.
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();
}
}
But, as I'm looking at this, there is no need to move the Create method to its own Factory class (although I think that it is preferrable -separation of concerns-), you can put it in the Fruit class:
public abstract class Fruit
{
public abstract string Define();
public static T CreateFruit<T>() where T : Fruit, new()
{
return new T();
}
}
And, to see if it works:
class Program
{
static void Main( string[] args )
{
Console.WriteLine (Fruit.CreateFruit<Apple> ().Define ());
Console.WriteLine (Fruit.CreateFruit<Orange> ().Define ());
Console.ReadLine ();
}
}