Что корректное альтернативно к наследованию статического метода?

Если Ваша функция возвращает значение через ссылку, компилятор не может сохранить его в регистре при вызывании других функций, потому что, теоретически, первая функция может сохранить адрес переменной, переданной ему в глобально доступной переменной, и вызванные функции любого subsecuently могут изменить его, таким образом, компилятор будет иметь (1) сохраняют значение от регистров назад к памяти прежде, чем вызвать другие функции и (2) перечитает его, когда это будет необходимо от памяти снова после любого из таких вызовов.

, Если Вы возвращаетесь ссылкой, оптимизация Вашей программы пострадает

79
задан yoozer8 20 March 2013 в 14:43
поделиться

7 ответов

Одна идея:

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();

Никаких дополнительных фабричных классов не требуется.

59
ответ дан 24 November 2019 в 10:19
поделиться

Почему бы не создать класс фабрики (шаблонный) с помощью метода создания?

FruitFactory<Banana>.Create();
4
ответ дан 24 November 2019 в 10:19
поделиться

Я бы сделал что-то вроде этого

 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
ответ дан 24 November 2019 в 10:19
поделиться

Класс 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/");

Лично я считаю, что это хороший способ решить проблему,

3
ответ дан 24 November 2019 в 10:19
поделиться

Прежде всего, отсутствие статических инициализаторов, которые могут быть виртуальными, не означает, что у вас не может быть «стандартных» методов-членов, которые могут быть перегружены. Во-вторых, вы можете вызывать свои виртуальные методы из конструкторов, и они будут работать должным образом, так что здесь нет никаких проблем. В-третьих, вы можете использовать дженерики для создания типобезопасной фабрики.
Вот код, который использует метод 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());
    }
}
3
ответ дан 24 November 2019 в 10:19
поделиться

Я бы сказал, что лучше всего создать виртуальный / абстрактный метод инициализации для класса фруктов, который необходимо вызвать, а затем создать внешний класс «фабрика фруктов» для создания экземпляров:


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;
    }
}
0
ответ дан 24 November 2019 в 10:19
поделиться

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 ();
        }        
    }
16
ответ дан 24 November 2019 в 10:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: