помочь с шаблоном c # - PullRequest
1 голос
/ 28 ноября 2009

Здравствуйте и спасибо за любую помощь.

с использованием .Net 3.5 C #;

Скажем, у меня есть около 10 методов, которые следуют одному и тому же шаблону

Используя 3 в качестве примера:

public Customer CreateCustomer(Customer c) { .. }
public Car CreateCar(Car c) { .. }
public Planet CreatePlanet(Planet p) { ..}

внутренняя логика каждого метода имеет точно такой же шаблон.

IE:

public Customer CreateCustomer(Customer c)
{
Log.BeginRequest(c, ActionType.Create); 
Validate(customer);
WebService.Send(Convert(c));
Log.EndRequest(c, ActionType.Create); 
}

public Car CreateCar(Car c)
{
Log.BeginRequest(c, ActionType.Create); 

Validate(c);

WebService.Send(Convert(c));

Log.EndRequest(c, ActionType.Create); 
}

То же самое верно для CreatePlanet и других 7 методов.

Можно ли переписать эти методы, все они следуют одному и тому же шаблону, и я чувствую, что что-то упустил ... Есть ли еще один уровень абстракции, который можно получить?

Вопрос: Как это следует переписать, чтобы воспользоваться преимуществами правильной архитектуры?

Спасибо, Стивен

Ответы [ 8 ]

7 голосов
/ 28 ноября 2009

Это похоже на случай, который соответствует шаблону шаблона . Вы можете заставить все объекты реализовывать один и тот же интерфейс / базу и выполнять действие с интерфейсом.

Я предполагаю, что единственная часть, которая должна знать фактический тип, это Validate(). Это можно решить двумя способами:

  1. Наличие интерфейса / базы объявить Validate и затем внедрить его в каждом конкретном объекте.
  2. Определение отображения стратегии между типом конкретной сущности и фактической стратегией проверки.

Пример использования абстрактной проверки базового класса -

База сущности, в которой есть внутренний сервис для создания и абстрактное определение для валидации:

public abstract class EntityBase
{
    protected abstract void Validate();

    protected void Create(EntityBase c)
    {
        Log.BeginRequest(c, ActionType.Create);
        c.Validate();
        WebService.Send(Convert(c));
        Log.EndRequest(c, ActionType.Create); 
    }
}

Конкретный разработчик с проверкой функциональности:

public class Customer : EntityBase
{
    private int year;

    public Customer(int year)
    {
        this.year = year;
    }

    public void CreateCustomer(Customer c)
    {
        Create(c);
    }

    protected override void Validate()
    {
        if (year < 1900)
        {
            throw new Exception("Too old");
        }
    }
}

Я не видел в исходном коде, что возвращает Create, поэтому я изменил его на void, чтобы сделать пример понятным

2 голосов
/ 28 ноября 2009

Я думаю, что вы ищете универсальный метод решение.

public T Create<T>(T t)
{
    Log.BeginRequest(t, ActionType.Create); 
    Validate(t);
    WebService.Send(Convert(t));
    Log.EndRequest(t, ActionType.Create);
    return t;
}
1 голос
/ 28 ноября 2009
 public T Create<T>(T c)
 {
    Log.BeginRequest(c, ActionType.Create); 
    Validate(customer);
    WebService.Send(Convert(c));
    Log.EndRequest(c, ActionType.Create); 
 }
1 голос
/ 28 ноября 2009

Да, с общей функцией:

  public T TrackInstantiation<T>(T entity)
  {
    Log.BeginRequest(entity, ActionType.Create); 
    Validate(entity);
    WebService.Send(Convert(entity));
    Log.EndRequest(entity, ActionType.Create);
    // Don't you also need to return the thing to fulfill the method siugnature ?
    return entity;
  }

Я изменил имя метода, потому что вы не Создаете объект в этом методе (вы передаете уже созданный экземпляр), вы просто проверяете, сохраняете и регистрируете его создание. Кстати, почему бы не создать объект здесь? Тогда это будет близко к шаблону, называемому Abstract Factory .

Вы также можете сделать то же самое, используя интерфейс.

открытый интерфейс ICanBeTracked {/ * нет методов * /}

Измените каждый из типов, которые вы хотите передать этому методу, чтобы они также переопределяли этот интерфейс. Затем просто напишите ваш метод

  public ICanBeTracked TrackInstantiation(ICanBeTracked  entity)
  {
    Log.BeginRequest(entity, ActionType.Create); 
    Validate(entity);
    WebService.Send(Convert(entity));
    Log.EndRequest(entity, ActionType.Create);
    // Don't you also need to return the thing to fulfill the method siugnature ?
    return entity;
  }

... И сделать перегрузку для каждого из трех методов, вызываемых описанным выше методом, с входным параметром, типизированным как ссылка ICanBeTracked

0 голосов
/ 28 ноября 2009

Вы можете использовать Аспектно-ориентированное программирование для применения регистрации и проверки. Используя PIAB (блок приложения внедрения политики) (часть Enterprise Library) из команды Microsoft Patterns & Practices (и при условии, что конфигурация была на месте), вы можете получить что-то вроде этого:

[LogRequest(ActionType.Create)]
[DoValidate()]
public T Create<T>(T item)
{
   WebService.Send(convert(item));
}

где LogRequest - это пользовательский атрибут, который устанавливает новый ICallHandler, в котором будет регистрироваться начало запроса, вызывается getNext() (который отправляет управление следующему ICallHandler по цепочке или если это был последний в цепочке , передает управление вызываемому методу), затем, когда управление было возвращено ICallHandler, оно регистрирует конец запроса.

Валидация может быть обработана блоком приложения валидации, который без проблем работает с PIAB или вы можете написать свои собственные обработчики проверки

AOP может существенно сократить объем кода, который вам нужен, но будьте осторожны, чтобы не переборщить с ним.

Вы можете прочитать о библиотеке Предприятия здесь: http://www.codeplex.com/entlib/

0 голосов
/ 28 ноября 2009

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

Если это так, у вас есть несколько вариантов. Один из них - просто перегрузить функции Validate / Convert и позволить решению системы перегрузки системы типов определить, какой из них вызывать. Другой (и это предпочтительный вариант) - использовать шаблон шаблона, рекомендованный ранее, и просто использовать каждый из ваших типов для реализации общего интерфейса. И третий вариант - запросить параметр делегата для функции для каждого из ваших методов. У вас уже есть примеры первых двух, поэтому вот пример кода для того, как написать метод для приема делегатов:

public T Create<T>(T c, Action<T> validate, Func<T, string> convert)
{
    Log.BeginRequest(c, ActionType.Create);

    validate(c);
    WebService.Send(convert(c));

    Log.EndRequest(c, ActionType.Create);
}
0 голосов
/ 28 ноября 2009

Вы можете извлечь общий интерфейс для этих десяти типов, если только тип отличается или вы можете создать универсальный метод.

0 голосов
/ 28 ноября 2009

Вы можете использовать универсальные методы:

T Create<T>(T arg)

Или просто System.Object:

object Create(object arg);
{
   Log.BeginRequest(arg, ActionType.Create); 
   Validate(arg);
   WebService.Send(Convert(arg));
   Log.EndRequest(arg, ActionType.Create); 
   return arg; //It must have a return
}

Car CreateCar(Car c)
{
   return (Car)Create(c);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...