#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 спасибо, я знаю, что он скрыт, но я чувствую, что на данном этапе я могу положиться на него, посмотрим, смогу ли я сделать это лучше на каком-то другом этапе.