C # с использованием Activator.Как создать шаблон фабрики установки

#c# #asp.net-mvc #design-patterns #factory-pattern

#c# #asp.net-mvc #шаблоны проектирования #factory-pattern

Вопрос:

У меня есть класс пользователя, скажем, User

 public class User
{
public int Id {get;set;}   
public string Name {get;set;}

}
 

и интерфейс, который возвращает группу пользователей, просматривая идентификатор данного пользователя

 public intervace IPeople
{
   IList<User> GetPeople (int id);
   string Key {get;}
}
 

Вот несколько реализаций IPeople

 public class Friends : IPeople
{
   public IList<User> GetPeople (int id)
   {
      return ListOfUsersWhoAreFriends();
   }

    public string Key {get { return "Friends"; }
}


public class Fans : IPeople
{
   public IList<User> GetPeople (int id)
   {
      return ListOfFans();
   }
   public string Key {get { return "Fans"; }

}
 

Теперь в моем методе вызова

  string key="SomeKey" ; //It could be friends or fans
 int id =1;
 IPeople[] allPeople = GetAllInstancesOf<IPeople>();

 IList<User> requiredUsers = allPeople.FirstOrDefault(m=>m.Key == key).GetPeople(id);
 

Так сказать, я создаю экземпляры всех производных классов, а затем проверяю, какой из них мне нужен,
прежде чем вызывать для него функцию. Он работает нормально, но я чувствую, что с точки
зрения производительности это не очень хорошее решение, поскольку я создаю экземпляр путем отражения. Каков лучший способ добиться этого. Какой-нибудь заводской метод, если да, то как??

Помощь будет оценена.

С уважением

Parminder

Ответ №1:

Я предполагаю, что вы используете отражение в своем классе GetAllInstancesOf? Не уверен, откуда вы заполняете свой список людей или зачем вам нужны ключ и идентификатор, но для заводского шаблона в данном случае я бы использовал следующее

 public IList<User> UserFactory(string kindOfPeople)
{
  switch (kindOfPeople.ToLower())
  {
    case "fans":
      return ListOfFans();
    case "friends":
      return ListOfUsersWhoAreFriends();
    default:
      return new List<User>();
  }
}
 

Если типы людей (фанаты, друзья, семья и т. Д.) Ограничены и не меняются очень часто в вашем приложении, тогда я бы сделал это перечислением и передал его на фабрику

 public enum KindsOfPeople { Friends = 0, Fans = 1}
 

PS: Предполагается, что и поклонники, и друзья являются производными от класса User. Это не было показано в вашем коде. Хороший способ использования заводского шаблона — если все возможные классы, возвращаемые с фабрики, наследуются от общего базового класса.

Комментарии:

1. спасибо Чайтанья, но мне не нравятся Ifs, switch и перечисления здесь. подумайте, что, если я захочу создать новый тип людей, нужно будет снова изменить код.

2. @Parminder Как вы думаете, что происходит в вашем ответе Autofac? Все виды Ifs, переключателей, хэш-таблиц и т. Д. Вы просто удалены из него.

3. С вашим ответом Autofac вам все равно придется изменять код, когда вам все равно нужно создавать новый тип. Если вы хотите избежать этого, вам следует зарегистрировать классы с помощью файла конфигурации. Не уверен насчет Autofac, но некоторые другие контейнеры DI (внедрение зависимостей), такие как Spring. Net позволит вам сделать это как в коде, так и в конфигурации.

4. @LarsTech спасибо за отзыв. Я могу понять, что вы говорите. Но, по крайней мере, я настраиваю вещи, используя некоторый конфигурационный файл на более позднем этапе. Кроме того, если я в конечном итоге делаю то же самое, что и Autofac, лучше использовать его, а не изобретать заново.

Ответ №2:

Я чувствую, что нашел лучшее решение. Вот оно.

 public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public interface IPeople
{
    IList<User> GetPeople(int id);

}


public class Friends : IPeople
{
    public IList<User> GetPeople(int id)
    {
        return new List<User>();
    }



    public class Fans : IPeople
    {
        public IList<User> GetPeople(int id)
        {
            return new List<User>();
        }
    }


    public class Program
    {
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<Friends>().Named<IPeople>("Friends");
            builder.RegisterType<Fans>().Named<IPeople>("Fans");

            IContainer c = builder.Build();

            var x = c.ResolveNamed<IPeople>("Friends");

        }
    }
}
 

Поскольку я использую Autofac, я слежу за регистром с именованными ключами.

Спасибо

Комментарии:

1. Я не знаю autofac, поэтому не могу сказать, что он делает, но очень возможно, что он все равно будет использовать отражение для создания нового экземпляра данной реализации IPeople при каждом вызове ResolveNamed . Итак, если вы беспокоитесь о производительности, вы просто скрыли проблему. Прежде чем вносить какие-либо изменения, связанные с производительностью, вы должны измерить, действительно ли это имеет значение. Создание экземпляра объекта не требует больших затрат (особенно если он не работает в конструкторе).

2. @marcind спасибо, я знаю, что он скрыт, но я чувствую, что на данном этапе я могу положиться на него, посмотрим, смогу ли я сделать это лучше на каком-то другом этапе.