#c# #oop #design-patterns
#c# #ооп #шаблоны проектирования
Вопрос:
Допустим, у меня есть следующий интерфейс
interface ILeague
{
string ShowSquad();
}
Следующие классы, реализующие их
class EPL : ILeague
{
public string ShowSquad()
{
return "EPL players collection";
}
}
class LaLiga: ILeague
{
public string ShowSquad()
{
return "La-liga player Collection";
}
}
я использую этот интерфейс, как показано ниже
public string ShowLeaguePlayers(ILeague leagueDataProvider)
{
return leagueDataProvider.ShowSquad();
}
Теперь, в зависимости от лиги, в которой я нахожусь, я хочу показывать разные данные. Иногда EPL, а иногда LaLiag. Это переключение может произойти в том же цикле выполнения.
Я попробовал следующий подход
class LeagueDataProvider : ILeague
{
private ILeague m_Provider;
private string league;
private void SetContext()
{
// Have some logic to figure out the league
league = "EPL";
if (league.Equals("EPL"))
{
m_Provider = new EPL();
}
else
{
m_Provider = new LaLiga();
}
}
public string ShowSquad()
{
SetContext();
return m_Provider.ShowSquad();
}
}
Я изменил свой клиентский код следующим образом
void ShowData()
{
ILeague Dataprovider = new LeagueDataProvider();
Console.WriteLine(ShowLeaguePlayers(Dataprovider));
}
// copied again for easy viewing
public string ShowLeaguePlayers(ILeague leagueDataProvider)
{
return leagueDataProvider.ShowSquad();
}
Это работает нормально, но каждый раз, когда я вызываю ShowSquad , он должен проверять наличие лиги и извлекать данные. Есть ли лучший способ сделать это?
Чего я пытаюсь достичь здесь :
В зависимости от лиги, я хочу получать разные данные при вызове ShowSquad . Я должен иметь возможность издеваться над ILeague в UT, и в будущем может появиться еще много реализаций ILeague, поэтому я хочу избежать модификации и повторного тестирования компонентов, которые их используют
Комментарии:
1. Да, трудно понять, почему вы разработали это именно так, какие проблемы вы разделяли и чего вы пытались достичь. Вероятно, вы хотели бы, чтобы ваш
LeagueDataProvider
был универсальным классом. хотя это трудно сказать2. Я должен быть в состоянии издеваться над ILeague в моем UT. Это основная причина, по которой я рефакторингую этот код. И другая причина в том, что в будущем может появиться еще много реализаций ILeague, поэтому я хочу избежать модификации классов, которые их используют в будущем
3. Я бы не стал создавать
LeagueDataProvider
anILeague
, потому что это не так. Это более или менее своего рода фабрика. Вы хотите, чтобы он содержал или создавалILeague
, а не реализовывал один. Google «пример шаблона фабрики классов c #»4. @Andy Это была моя первоначальная мысль, сделать LeagueDataProvider в качестве фабрики, которая возвращает ILeague, которую я могу использовать. Но чтобы написать UT, я должен заставить свою фабрику реализовать интерфейс и издеваться над ним в моем UT. Я не был так уверен, что его хорошая практика для фабрики должна реализовывать интерфейс
5. Вы могли бы заставить его реализовать интерфейс. Нравится
public interface ILeagueFactory { ILeague CreateLeague(); }
Ответ №1:
Возможно, попробуйте использовать заводской шаблон: интерфейсы:
interface ILeague
{
string ShowSquad();
}
interface ILeagueFactory
{
ILeague CreateLeague();
}
реализации:
class EPL : ILeague
{
public string ShowSquad()
{
return "EPL players collection";
}
}
class LaLiga: ILeague
{
public string ShowSquad()
{
return "La-liga player Collection";
}
}
class EPLFactory : ILeagueFactory
{
public ILeague CreateLeague()
{
return new EPL();
}
}
class LaLigaFactory : ILeagueFactory
{
public ILeague CreateLeague()
{
return new LaLiga();
}
}
Чтобы получить фабрику rigth league, вы можете обернуть нужные вам фабрики в коллекцию :
class LeagueFactoryCollection
{
private IDictionary<string, ILeagueFactory> factories;
public LeagueFactoryCollection()
{
factories = new Dictionary<string, ILeagueFactory>();
}
public void Add(string key, ILeagueFactory factory)
{
factories.Add(key, factory);
}
public ILeagueFactory Get(string key)
{
return factories[key];
}
}
Теперь вы сможете проще добавлять новые типы лиг:
//define your needed factories
var leagueCollections = new LeagueFactoryCollection();
leagueCollections.Add("EPL", new EPLFactory());
leagueCollections.Add("LaLiga", new LaLigaFactory());
//consumer
leagueCollections.Get("EPL").CreateLeague().ShowSquad();
Ваш потребитель не изменится, когда вы добавите новую лигу