Как и в случае со всеми проблемами, дизайн может помочь вам адаптироваться к ситуациям, которые вы не рассматривали намного быстрее, чем общее решение.
Начните с написания чего-то, что анализирует данные одного провайдера - того, который имеет самый простой формат для обработки Найдите способ адаптировать этот обработчик к вашему сканеру. Обязательно инкапсулируйте конструкцию - вы всегда должны это делать ...
public class RoomTypeExtractor
{
private RoomTypeExtractor() { }
public static RoomTypeExtractor GetInstance()
{
return new RoomTypeExtractor();
}
public string GetRoomType(string content)
{
// BEHAVIOR #1
}
}
Метод GetInstance()
позволяет вам перейти к шаблону Стратегии практически бесплатно.
Затем добавьте ваш второй тип провайдера. Скажем, например, что у вас есть немного более сложный формат данных, который немного более распространен, чем первый формат. Начните с рефакторинга того, что было вашим конкретным классом экстрактора типа комнаты, в абстракцию с единственным вариантом позади него, и пусть метод GetInstance()
возвращает экземпляр конкретного типа:
public abstract class RoomTypeExtractor
{
public static RoomTypeExtractor GetInstance()
{
return SimpleRoomTypeExtractor.GetInstance();
}
public abstract string GetRoomType(string content);
}
public final class SimpleRoomTypeExtractor extends RoomTypeExtractor
{
private SimpleRoomTypeExtractor() { }
public static SimpleRoomTypeExtractor GetInstance()
{
return new SimpleRoomTypeExtractor();
}
public string GetRoomType(string content)
{
// BEHAVIOR #1
}
}
Создание другого варианта, который реализует шаблон Null Object ...
public class NullRoomTypeExtractor extends RoomTypeExtractor
{
private NullRoomTypeExtractor() { }
public static NullRoomTypeExtractor GetInstance()
{
return new NullRoomTypeExtractor();
}
public string GetRoomType(string content)
{
// whatever "no content" behavior you want... I chose returning null
return null;
}
}
Добавьте базовый класс, который облегчит работу с шаблоном цепочки ответственности, который находится в этой проблеме:
public abstract class ChainLinkRoomTypeExtractor extends RoomTypeExtractor
{
private final RoomTypeExtractor next_;
protected ChainLinkRoomTypeExtractor(RoomTypeExtractor next)
{
next_ = next;
}
public final string GetRoomType(string content)
{
if (CanHandleContent(content))
{
return GetRoomTypeFromUnderstoodFormat(content);
}
else
{
return next_.GetRoomType(content);
}
}
protected abstract bool CanHandleContent(string content);
protected abstract string GetRoomTypeFromUnderstoodFormat(string content);
}
Теперь, сделайте рефакторинг исходной реализации, чтобы иметь базовый класс, который объединит его в цепочку ответственности ...
public final class SimpleRoomTypeExtractor extends ChainLinkRoomTypeExtractor
{
private SimpleRoomTypeExtractor(RoomTypeExtractor next)
{
super(next);
}
public static SimpleRoomTypeExtractor GetInstance(RoomTypeExtractor next)
{
return new SimpleRoomTypeExtractor(next);
}
protected string CanHandleContent(string content)
{
// return whether or not content contains the right format
}
protected string GetRoomTypeFromUnderstoodFormat(string content)
{
// BEHAVIOR #1
}
}
Обязательно обновите RoomTypeExtractor.GetInstance()
:
public static RoomTypeExtractor GetInstance()
{
RoomTypeExtractor extractor = NullRoomTypeExtractor.GetInstance();
extractor = SimpleRoomTypeExtractor.GetInstance(extractor);
return extractor;
}
Как только это будет сделано, создайте новую ссылку для Цепочки ответственности ...
public final class MoreComplexRoomTypeExtractor extends ChainLinkRoomTypeExtractor
{
private MoreComplexRoomTypeExtractor(RoomTypeExtractor next)
{
super(next);
}
public static MoreComplexRoomTypeExtractor GetInstance(RoomTypeExtractor next)
{
return new MoreComplexRoomTypeExtractor(next);
}
protected string CanHandleContent(string content)
{
// Check for presence of format #2
}
protected string GetRoomTypeFromUnderstoodFormat(string content)
{
// BEHAVIOR #2
}
}
Наконец, добавьте новую ссылку в цепочку. Если это более распространенный формат, вы можете придать ему более высокий приоритет, разместив его в цепочке выше (реальные силы, которые управляют порядком цепочки, станут очевидными. когда вы сделаете это):
public static RoomTypeExtractor GetInstance()
{
RoomTypeExtractor extractor = NullRoomTypeExtractor.GetInstance();
extractor = SimpleRoomTypeExtractor.GetInstance(extractor);
extractor = MoreComplexRoomTypeExtractor.GetInstance(extractor);
return extractor;
}
Со временем вы можете захотеть добавить способы динамически добавлять новые ссылки в Цепочку ответственности, как указал Cletus, но фундаментальным принципом здесь является Emergent Design . Начните с высокого качества. Держите качество высоким. Гоняй с тестами. Сделайте эти три вещи, и вы сможете использовать механизм нечеткой логики между вашими ушами, чтобы преодолеть практически любую проблему ...
EDIT
Переведено на Java. Надеюсь, я сделал это правильно; Я немного ржавый.