подскажите подходяший шаблон.
От: RobinHood  
Дата: 19.08.13 15:33
Оценка:
Всем доброго времени суток.
1) у меня есть набор действий (операций) которые может производить система. Этот набор может изменится со временем.
2) У меня есть набор типов данных над которыми может производится данные действия.

Пример:
набор действий: Command1 , Command2 , Command3
набор типов данных: DataType1, DataType2, DataType3

в данном примере к данным:
На вход приходит тип данных:
В случае:
DataType1 — этот тип обрабатывает Command1
DataType2 — этот тип обрабатывает Command1 , Command2
DataType3 — этот тип обрабатывает Command1 , Command3

Что нужно: создать обьектную модель с возможностью расширения/сокрашения набора действий и типов данных.
хотелось бы избежать ветвяшихся if/else и иметь как можно более гибкую модель к расширению. Смотрел: Strategy and Command patterns,
но ето не совсем мой случай

Заранее спасибо.
Re: подскажите подходяший шаблон.
От: artelk  
Дата: 19.08.13 15:46
Оценка:
Здравствуйте, RobinHood, Вы писали:

Первое, что пришло в голову:

private Dictionary<Type, List<Action<object>>> commands = ...;

public void DoCommands(object data)
{
   List<Action<object>> dataCommands;
   if(commands.TryGet(data.GetType(), out dataCommands))
      dataCommands.ForEach(cmd => cmd(data));
}
Re[2]: подскажите подходяший шаблон.
От: RobinHood  
Дата: 19.08.13 21:17
Оценка:
Здравствуйте, artelk, Вы писали:

A>Здравствуйте, RobinHood, Вы писали:


A>Первое, что пришло в голову:


A>
A>private Dictionary<Type, List<Action<object>>> commands = ...;

A>public void DoCommands(object data)
A>{
A>   List<Action<object>> dataCommands;
A>   if(commands.TryGet(data.GetType(), out dataCommands))
A>      dataCommands.ForEach(cmd => cmd(data));
A>}
A>


Я работаю с ява.
конструкция Action — это как я понимаю из с#? Можно расписать подробнее и без привязки к языку.
Заранее спасибо.
Re[3]: подскажите подходяший шаблон.
От: artelk  
Дата: 19.08.13 21:36
Оценка: 3 (1)
Здравствуйте, RobinHood, Вы писали:

RH>Я работаю с ява.

RH>конструкция Action — это как я понимаю из с#? Можно расписать подробнее и без привязки к языку.
RH>Заранее спасибо.
Тогда вместо Action можно сделать интерфейс IAction или ICommand:

interface ICommand
{
  void Invoke(object arg);
}

//В Java не копенгаген, так что только опишу идею:

private Dictionary<Type, List<ICommand> commands = ...;

public void DoCommands(object data)
{
   List<ICommand> dataTypeCommands;
   if(commands.TryGet(data.GetType(), out dataTypeCommands))
     foreach(var cmd in dataTypeCommands)
       cmd.Invoke(data);
}

public void RegisterCommand(Type dataType, ICommand command)
{
   List<ICommand> dataTypeCommands;
   if(!commands.TryGet(dataType, out dataCommands))
     commands.Add(dataType, dataTypeCommands = new List<ICommand>());
   dataTypeCommands.Add(dataType, command);
}


В Java, на сколько помню, можно по месту делать реализацию интерфейса и даже вроде замыкания есть (для final переменных), так что будет относительно немногословно.
Re: подскажите подходяший шаблон.
От: . Великобритания  
Дата: 20.08.13 10:22
Оценка: 2 (1)
Здравствуйте, RobinHood, Вы писали:

RH>Всем доброго времени суток.

RH> 1) у меня есть набор действий (операций) которые может производить система. Этот набор может изменится со временем.
RH> 2) У меня есть набор типов данных над которыми может производится данные действия.

RH>Пример:

RH> набор действий: Command1 , Command2 , Command3
RH> набор типов данных: DataType1, DataType2, DataType3

RH>в данном примере к данным:

RH>На вход приходит тип данных:
RH> В случае:
RH> DataType1 — этот тип обрабатывает Command1
RH> DataType2 — этот тип обрабатывает Command1 , Command2
RH> DataType3 — этот тип обрабатывает Command1 , Command3

RH>Что нужно: создать обьектную модель с возможностью расширения/сокрашения набора действий и типов данных.

RH>хотелось бы избежать ветвяшихся if/else и иметь как можно более гибкую модель к расширению. Смотрел: Strategy and Command patterns,
RH>но ето не совсем мой случай

RH>Заранее спасибо.

Может Visitor? Что-то типа:
interface DataVisitor
{
   void accept(DataType1 dt);
   void accept(DataType2 dt);
   void accept(DataType3 dt);
}

class DataType1
{
   void visit(DataVisitor v) {v.accept(this);}
}

class DataType2
{
   void visit(DataVisitor v) {v.accept(this);}
}

class DataType3
{
   void visit(DataVisitor v) {v.accept(this);}
}

class DefaultDataVisitor implements DataVisitor
{
   void accept(DataType1 dt)
   {//do nothing}
   void accept(DataType2 dt)
   {//do nothing}
   void accept(DataType3 dt)
   {//do nothing}
}

// это важная команда, она implements - при добавлении нового типа - компилятор заставит имплементировать метод для него.
class Command1 implements DataVisitor
{
   void accept(DataType1 dt)
   {
     use(dt);
   }
   void accept(DataType2 dt)
   {
     use(dt);
   }
   void accept(DataType3 dt)
   {
     use(dt);
   }
}
// а эти команды переопределяют только нужные методы.
class Command2 extends DefaultDataVisitor
{
   void accept(DataType1 dt)
   {
     use(dt);
   }
   void accept(DataType2 dt)
   {
     use(dt);
   }
}
class Command3 extends DefaultDataVisitor
{
   void accept(DataType1 dt)
   {
     use(dt);
   }
   void accept(DataType3 dt)
   {
     use(dt);
   }
}


Вместо "do nothing" можно кидать исключение, можно вместо void возвращать какой-то статус — обработано ли, а можно даже и Action.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[2]: подскажите подходяший шаблон.
От: artelk  
Дата: 20.08.13 13:00
Оценка:
Здравствуйте, ., Вы писали:

.>Здравствуйте, RobinHood, Вы писали:


RH>>Что нужно: создать обьектную модель с возможностью расширения/сокрашения набора действий и типов данных.

.>Может Visitor? Что-то типа:

Expression problem
Добавление нового типа данных потребует добавления метода в interface DataVisitor со всеми вытекающими.
Кроме того, у типов данных обязан быть метод visit, что не всегда возможно (в моей реализации спец методов не требуется).
Но добавление новой команды будет делаться легко.

Можно было бы сделать наоборот (тоже с добавлением методов в DataTypes), чтоб добавление нового типа данных делалось легко (за счет усложнения добавления новой команды).
Классический ООП-полиморфизм:


class DataTypeBase
{
  //дефолтные реализации ничего не делают
  virtual void DoCommand1() {}
  virtual void DoCommand2() {}
  virtual void DoCommand3() {}
}

class DataType1 : DataTypeBase
{
  override void DoCommand2() { /*use*/ }
}

class DataType2 : DataTypeBase
{
  override void DoCommand1() { /*use*/ }
  override void DoCommand3() { /*use*/ }
}
Re: подскажите подходяший шаблон.
От: Blazkowicz Россия  
Дата: 20.08.13 13:11
Оценка: 2 (1)
Здравствуйте, RobinHood, Вы писали:

RH> 1) у меня есть набор действий (операций) которые может производить система. Этот набор может изменится со временем.

По очереди? Независимо? Взаимозаменяемо?

RH> 2) У меня есть набор типов данных над которыми может производится данные действия.

Ну, то есть они и сами могут это производить, как написано ниже?

RH>Пример:

RH> набор действий: Command1 , Command2 , Command3
RH> набор типов данных: DataType1, DataType2, DataType3
Конкретики не нашлось? В вопросе "на пальцах" выходит и ответ "на пальцах".


RH>в данном примере к данным:

RH>На вход приходит тип данных:
RH> В случае:
RH> DataType1 — этот тип обрабатывает Command1
RH> DataType2 — этот тип обрабатывает Command1 , Command2
RH> DataType3 — этот тип обрабатывает Command1 , Command3
То есть "данные", имеют методы, в которые получают команду и выполняют команду, применяя своё состояние?


RH>Что нужно: создать обьектную модель с возможностью расширения/сокрашения набора действий и типов данных.

Любой IoC конфиг + абстрактные интерфейсы вроде Callable/Runnable.

RH>хотелось бы избежать ветвяшихся if/else и иметь как можно более гибкую модель к расширению.

if/else чудесно заменяются на HashMap и полиморфизм.

RH>Смотрел: Strategy and Command patterns,

RH>но ето не совсем мой случай
Так и не понятно что именно "твой случай". В чем заключается проблема? В расширении модели? Так это IoC DI чудесно решает.
"Комманда" позволяет отвязать отправителя и получателя. Если у тебя отправитель ничего не знает о DataType, то "Комманда" может помочь.
"Стратегия" инкапсулирует алгоритм. Подходит для случаем когда одно и тоже делается разными способами. Но, не зная в чем именно заключаются "Command1..3", понять нужна ли тут "стратегия" сложно.
Re[3]: подскажите подходяший шаблон.
От: . Великобритания  
Дата: 20.08.13 13:47
Оценка:
Здравствуйте, artelk, Вы писали:

RH>>>Что нужно: создать обьектную модель с возможностью расширения/сокрашения набора действий и типов данных.

.>>Может Visitor? Что-то типа:
A>Expression problem
Так оно и не решается без рантайм-ошибок/рефлексии в с#/java, насколько я знаю. Я же привёл чистое ООП решение.

A>Добавление нового типа данных потребует добавления метода в interface DataVisitor со всеми вытекающими.

Ну сколько надо, столько и вытечет. Expression Problem говорит, что это нельзя делать в независимых модулях, интерфейс должен знать о всех типах, что не всегда возможно, но можно создавать иерархию визиторов. Но когда возможно, лучше так и делать.

A>Кроме того, у типов данных обязан быть метод visit, что не всегда возможно (в моей реализации спец методов не требуется).

Это да, но можно присобачить адаптер.

A>Но добавление новой команды будет делаться легко.

Но зато меньше статических проверок компилятором. Может тогда проще динамический язык использовать...

A>Можно было бы сделать наоборот (тоже с добавлением методов в DataTypes), чтоб добавление нового типа данных делалось легко (за счет усложнения добавления новой команды).

A>Классический ООП-полиморфизм:
A> virtual void DoCommand1() {}
Так ровно это у меня и есть. Почитай мой код внимательнее, особенно класс DefaultDataVisitor.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[4]: подскажите подходяший шаблон.
От: artelk  
Дата: 20.08.13 14:50
Оценка:
Здравствуйте, ., Вы писали:

.>Здравствуйте, artelk, Вы писали:


A>>Кроме того, у типов данных обязан быть метод visit, что не всегда возможно (в моей реализации спец методов не требуется).

.>Это да, но можно присобачить адаптер.
+1
Но придется делать классы-адаптеры в количестве, равном числу типов данных.
Обобщенный адаптер (без рефликсии) сделать не получится:
interface DataVisitor
{
   void accept(DataVisitableAdapter<DataType1> dt);
   void accept(DataVisitableAdapter<DataType2> dt);
   void accept(DataVisitableAdapter<DataType3> dt);
}

class DataVisitAdapter<TDataType>
{
  public void visit(DataVisitor v) 
  {
    v.accept(this);//УПС
  }
}

На C# будет ошибка. На Java такой DataVisitor даже не скомпилится (из за type erasure).
Но на C++ такое сделать можно.

A>>Можно было бы сделать наоборот (тоже с добавлением методов в DataTypes), чтоб добавление нового типа данных делалось легко (за счет усложнения добавления новой команды).

A>>Классический ООП-полиморфизм:
A>> virtual void DoCommand1() {}
.>Так ровно это у меня и есть. Почитай мой код внимательнее, особенно класс DefaultDataVisitor.
Ну если "наоборот" == "ровно это"...

PS
Регистрацию в моем решении можно сделать так, чтобы в клиентском коде использование было типобезопасно:

//TODO: проверки на null расставить по вкусу

public void RegisterCommand<TData>(Action<TData> command)
{
   List<Action<object>> dataTypeCommands;
   if(!commands.TryGet(typeof(TData), out dataCommands))
     commands.Add(dataType, dataTypeCommands = new List<Action<object>>());
   dataTypeCommands.Add(dataType, o => command((TData)o));
}

public void DoCommands(object data)
{
   List<Action<object>> dataCommands;
   if(commands.TryGet(data.GetType(), out dataCommands))
      dataCommands.ForEach(cmd => cmd(data));
}


Исключения InvalidCastException из-за приведения к TData кидаться не будет.
Re[5]: подскажите подходяший шаблон.
От: . Великобритания  
Дата: 20.08.13 16:02
Оценка:
Здравствуйте, artelk, Вы писали:

A>Но придется делать классы-адаптеры в количестве, равном числу типов данных.

А куда деваться — только кодогенерация, рефлексия, макросы...

A>Но на C++ такое сделать можно.

Так почти compile-time кодогенерация и получается.

A>>>Классический ООП-полиморфизм:

A>>> virtual void DoCommand1() {}
.>>Так ровно это у меня и есть. Почитай мой код внимательнее, особенно класс DefaultDataVisitor.
A>Ну если "наоборот" == "ровно это"...
Не понял. У меня же то же самое:
class DefaultDataVisitor implements DataVisitor
{
   void accept(DataType1 dt)
   {//do nothing}
   void accept(DataType2 dt)
   {//do nothing}
   void accept(DataType3 dt)
   {//do nothing}
}
// а эти команды переопределяют только нужные методы.
class Command2 extends DefaultDataVisitor
{
   void accept(DataType1 dt)
   {
     use(dt);
   }
   void accept(DataType2 dt)
   {
     use(dt);
   }
//DataType3 не нужен
}

ведь все методы в Java виртуальные.

A>PS

A>Регистрацию в моем решении можно сделать так, чтобы в клиентском коде использование было типобезопасно:
Это ненитересно... Рефлексия, приведение типов.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re: подскажите подходяший шаблон.
От: Loooser Россия  
Дата: 20.08.13 16:45
Оценка:
Здравствуйте, RobinHood, Вы писали:

RH>Всем доброго времени суток.

RH> 1) у меня есть набор действий (операций) которые может производить система. Этот набор может изменится со временем.
RH> 2) У меня есть набор типов данных над которыми может производится данные действия.

RH>Пример:

RH> набор действий: Command1 , Command2 , Command3
RH> набор типов данных: DataType1, DataType2, DataType3

RH>в данном примере к данным:

RH>На вход приходит тип данных:
RH> В случае:
RH> DataType1 — этот тип обрабатывает Command1
RH> DataType2 — этот тип обрабатывает Command1 , Command2
RH> DataType3 — этот тип обрабатывает Command1 , Command3

RH>Что нужно: создать обьектную модель с возможностью расширения/сокрашения набора действий и типов данных.

RH>хотелось бы избежать ветвяшихся if/else и иметь как можно более гибкую модель к расширению. Смотрел: Strategy and Command patterns,
RH>но ето не совсем мой случай

RH>Заранее спасибо.


А почему strategy и command не подходят? Если все наборы известны до компиляции то у меня было бы как-то так:


abstract class Protocol : typeobject
{
    Type DataType { get; }
    List<ICommand> { get; }
}

class Protocol1 : Protocol
{
    Type DataType { return DataType1.GetType(); }
    List<ICommand> { return new List<ICommand>() { new Command1(); }
}

class Protocol2 : Protocol
{
    Type DataType { return DataType2.GetType(); }
    List<ICommand> { return new List<ICommand>() { new Command1(); new Command2(); }
}

class Protocol3 : Protocol
{
    Type DataType { return DataType3.GetType(); }
    List<ICommand> { return new List<ICommand>() { new Command1(); new Command3(); }
}

// usage
void Action(Type dataType)
{
    foreach (var protocol in typeobject<Protocol>.GetDerivedList())
    {
        if (dataType == protocol.DataType)
        {
            ExecuteCommands(protocol.Commands);
        }
    }
}
Re[6]: подскажите подходяший шаблон.
От: artelk  
Дата: 20.08.13 20:20
Оценка:
Здравствуйте, ., Вы писали:

.>Здравствуйте, artelk, Вы писали:


A>>>>Классический ООП-полиморфизм:

A>>>> virtual void DoCommand1() {}
.>>>Так ровно это у меня и есть. Почитай мой код внимательнее, особенно класс DefaultDataVisitor.
A>>Ну если "наоборот" == "ровно это"...
.>Не понял. У меня же то же самое:
<...>
.>ведь все методы в Java виртуальные.
Это понятно. Но у тебя куча методов в базовом визиторе с необходимостью добавлять еще один на каждый новый тип данных, а у меня — в базовом классе типов данных с необходимостью добавлять еще один на каждую новую команду.
Кроме этого, под команды я не завожу типов. Это "то же самое"?

A>>PS

A>>Регистрацию в моем решении можно сделать так, чтобы в клиентском коде использование было типобезопасно:
.>Это ненитересно... Рефлексия, приведение типов.
Рефлексии-то, можно сказать, и нет. GetType работает мгновенно — каждый объект содержит ссылку на его Type.
typeof(T) — вообще, по сути, константа времени компиляции.
И все это еще и инкапсулировано.
Re[7]: подскажите подходяший шаблон.
От: . Великобритания  
Дата: 20.08.13 22:46
Оценка:
Здравствуйте, artelk, Вы писали:

.>>ведь все методы в Java виртуальные.

A>Это понятно. Но у тебя куча методов в базовом визиторе с необходимостью добавлять еще один на каждый новый тип данных, а у меня — в базовом классе типов данных с необходимостью добавлять еще один на каждую новую команду.
A>Кроме этого, под команды я не завожу типов. Это "то же самое"?
А понял. Но только для небольшого числа команд прокатит. И вообще SRP не соблюдается, в типах данных появляется логика.

A>>>Регистрацию в моем решении можно сделать так, чтобы в клиентском коде использование было типобезопасно:

.>>Это ненитересно... Рефлексия, приведение типов.
A>Рефлексии-то, можно сказать, и нет. GetType работает мгновенно — каждый объект содержит ссылку на его Type.
A>typeof(T) — вообще, по сути, константа времени компиляции.
A>И все это еще и инкапсулировано.
Понятно, конечно, тоже вариант. Короче, мы тут спорим, а топикстартер пропал, что ему нужно так никто толком не знает.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[8]: подскажите подходяший шаблон.
От: artelk  
Дата: 21.08.13 07:57
Оценка:
Здравствуйте, ., Вы писали:

.>Здравствуйте, artelk, Вы писали:


A>>Кроме этого, под команды я не завожу типов. Это "то же самое"?

.>А понял. Но только для небольшого числа команд прокатит. И вообще SRP не соблюдается, в типах данных появляется логика.
+1

.>Понятно, конечно, тоже вариант. Короче, мы тут спорим, а топикстартер пропал, что ему нужно так никто толком не знает.

Когда появляется предмет спора, топикстартер уже не нужен!

Но раз уж он в суе был упомянут...
Я протелепал его так: ему нужна возможность динамически строить соответствие типов данных и команд и потом обрабатывать множество данных.
Т.е. что-то вроде:

//1. регистрируем

//2. берем откуда-то поток данных (или подписываемся на их источник)
var seq = ...

//3. обрабатываем
foreach(var data in seq)
  commandExecutor.DoCommands(data);


В случае статики (с кучей методов в классах типов данных) будет:

//3. обрабатываем
foreach(var data in seq)
{
  //вот такой вот ужас
  data.DoCommand1();
  data.DoCommand2();
  data.DoCommand3();
  //...
  data.DoCommandN();
}


В случае визитора будет не менее ужасно.
Re[9]: подскажите подходяший шаблон.
От: . Великобритания  
Дата: 21.08.13 08:51
Оценка: 2 (1)
Здравствуйте, artelk, Вы писали:

.>>Понятно, конечно, тоже вариант. Короче, мы тут спорим, а топикстартер пропал, что ему нужно так никто толком не знает.

A>Когда появляется предмет спора, топикстартер уже не нужен!
Хе.

A>Но раз уж он в суе был упомянут...

A>Я протелепал его так: ему нужна возможность динамически строить соответствие типов данных и команд и потом обрабатывать множество данных.
A>Т.е. что-то вроде:

A>В случае визитора будет не менее ужасно.

В случае визитора я бы сделал так:
interface Action
{
   void run();
}
interface DataVisitor
{
   Action accept(DataType1 dt);
   Action accept(DataType2 dt);
   Action accept(DataType3 dt);
}
interface DataType
{
  Action visit(DataVisitor v);
}

class DataType1 implements DataType
{
   Action visit(DataVisitor v) {return v.accept(this);}
}

class DataType2 implements DataType
{
   Action visit(DataVisitor v) {return v.accept(this);}
}

class DataType3 implements DataType
{
   Action visit(DataVisitor v) {return v.accept(this);}
}

class DefaultDataVisitor implements DataVisitor
{
   Action accept(DataType1 dt) {return null;}
   Action accept(DataType2 dt) {return null;}
   Action accept(DataType3 dt) {return null;}
}

// это важная команда, она implements - при добавлении нового типа - компилятор заставит имплементировать метод для него.
class Command1 implements DataVisitor
{
   Action accept(DataType1 dt)
   {
     return new Action()
     {
        void run()
        {
          use(dt);
        }
     }
   }
   Action accept(DataType2 dt)
   {
     return new Action()
     {
        void run()
        {
          use(dt);
        }
     }
   }
   Action accept(DataType3 dt)
   {
     return new Action()
     {
        void run()
        {
          use(dt);
        }
     }
   }

}
// а эти команды переопределяют только нужные методы.
class Command2 extends DefaultDataVisitor
{
   Action accept(DataType1 dt)
   {
     return new Action()
     {
        void run()
        {
          use(dt);
        }
     }
   }
   Action accept(DataType2 dt)
   {
     return new Action()
     {
        void run()
        {
          use(dt);
        }
     }
   }
}
class Command3 extends DefaultDataVisitor
{
   Action accept(DataType1 dt)
   {
     return new Action()
     {
        void run()
        {
          use(dt);
        }
     }
   }
   Action accept(DataType3 dt)
   {
     return new Action()
     {
        void run()
        {
          use(dt);
        }
     }
   }
}
// используем:

List<DataVisitor> commands = availableCommands();
List<DataType> dataTypes = ...;
for(DataType dt : dataTypes)
{
  for(DataVisitor command : commands)
  {
     Action action = dt.visit(command);
     if(action != null)
       action.run(); // or put into a collection, sort, filter, etc.
  }
}

Притом интерфейс Action можно расширить, например добавив приоритеты команд, состояние enabled/disabled, проверку прав и т.п.
Вроде не так страшно, особенно использование.
Тип Action из визитора можно сделать generic, тогда эти визиторы можно будет использовать и для других целей.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[5]: подскажите подходяший шаблон.
От: . Великобритания  
Дата: 22.08.13 09:33
Оценка:
Здравствуйте, artelk, Вы писали:

A>>>Кроме того, у типов данных обязан быть метод visit, что не всегда возможно (в моей реализации спец методов не требуется).

.>>Это да, но можно присобачить адаптер.
A>+1
A>Но придется делать классы-адаптеры в количестве, равном числу типов данных.
A>Обобщенный адаптер (без рефликсии) сделать не получится:
A>На C# будет ошибка. На Java такой DataVisitor даже не скомпилится (из за type erasure).
A>Но на C++ такое сделать можно.
Что-то ты переусложняешь.
На Java можно использовать анонимные классы:
interface Visitor
{
    void accept(String s);
    void accept(Integer i);
    void accept(DataType1 dt1);
}
abstract class DataType
{
    abstract void accept(Visitor v);
}
class DataType1 extends DataType
{
    int a, b;

    DataType1(final int a, final int b) {
        this.a = a;
        this.b = b;
    }

    @Override
    void accept(final Visitor v) {
        v.accept(this);
    }
}
// и используем:

    List<DataType> dts = new ArrayList<DataType>();
    final Integer i = 42;
    dts.add(new DataType() {// Собственно адаптер.
        @Override
        void accept(final Visitor v) {
            v.accept(i);
        }
    });
    dts.add(new DataType1(3, 5));
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[6]: подскажите подходяший шаблон.
От: artelk  
Дата: 22.08.13 16:56
Оценка:
Здравствуйте, ., Вы писали:

.>Здравствуйте, artelk, Вы писали:


.>
.>    final Integer i = 42;
.>    dts.add(new DataType() {// Собственно адаптер.
.>        @Override
.>        void accept(final Visitor v) {
.>            v.accept(i);
.>        }
.>    });
.>

Мне нравится.
Правда остается проблема со случаем, когда последовательность данных приходит извне в виде, например, List<object> — т.е., например, десериализуется из потока.
Тогда будет либо switch\case, либо Dictionary<Type, Func<object, DataType>> с "рефлексией и приведением типов".
Кроме того, соответствие типов и комманд делается статически, что, помимо достоинств в виде проверки компилятором, обладает очевидными недостатками.
Короче, у всего есть границы применимости. Топикстартеру решать, какое решение для него более приемлемо, руководствуясь сценариями использования.
Re[7]: подскажите подходяший шаблон.
От: . Великобритания  
Дата: 22.08.13 17:31
Оценка:
Здравствуйте, artelk, Вы писали:

A>Мне нравится.

A>Правда остается проблема со случаем, когда последовательность данных приходит извне в виде, например, List<object> — т.е., например, десериализуется из потока.
A>Тогда будет либо switch\case, либо Dictionary<Type, Func<object, DataType>> с "рефлексией и приведением типов".
A>Кроме того, соответствие типов и комманд делается статически, что, помимо достоинств в виде проверки компилятором, обладает очевидными недостатками.
A>Короче, у всего есть границы применимости. Топикстартеру решать, какое решение для него более приемлемо, руководствуясь сценариями использования.
если приходит извне, и о типах никакой инфы, то понятное дело только рефлексия и молитва.
Кстати, с этим Dictionary по сравнению с `if(x instanceof DataType1)` обладает серьёзным недостатком — реальный Type может быть подтипом и поиск в Dictionary не сработает. А это может случиться не только в случае простого наследования, но и в тех же юнит-тестах с моками, AOP может нагенерить динамических прокси, какой-нибудь stub ремотные интерфейсы... В общем куча аккуратно запрятанных граблей.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[10]: подскажите подходяший шаблон.
От: RobinHood  
Дата: 25.08.13 21:22
Оценка:
Здравствуйте, ., Вы писали:

.>// используем:


.>List<DataVisitor> commands = availableCommands();

.>List<DataType> dataTypes = ...;
.>for(DataType dt : dataTypes)
.>{
.> for(DataVisitor command : commands)
.> {
.> Action action = dt.visit(command);
.> if(action != null)
.> action.run(); // or put into a collection, sort, filter, etc.
.> }
.>}
.>[/java]
.>Притом интерфейс Action можно расширить, например добавив приоритеты команд, состояние enabled/disabled, проверку прав и т.п.
.>Вроде не так страшно, особенно использование.
.>Тип Action из визитора можно сделать generic, тогда эти визиторы можно будет использовать и для других целей.


Прежде всего хотел сказать всем спасибо за интересные решения и извенится что начал пост и на время пропал.

Более конкретно на счет моей задачи.
1)У меня есть пользователи -- это тип данных.

2)Мне нужно расчитывать активность пользователей по различным критериям
Расчеты ведутся в для различных временных промежутков: 1минута , 10минут , 30мин , 2часа , 1день .....

Начаньные требования к системе:
Расчет активности пользователя — (различные статистические алгоритмы) зависит от временных промежутков -- Комманды.

Т.е для 1минуты будет алгоритм А , для 2 часов будет алгоритм Б.

3) алгоритмов расчета активности для одного и того же временного промежутка может быть несколько:
для промежутка 10минут может пременятся алгоритм А и затем над результатом Алгоритм В. ==> порядок алгоритмов -- команд важен, и также есть случаи что результат одного алгоритма будет входными данными для другого.

Учитывая что система на ранней стадии мне меняют/добавляют условия очень часто:
Например:
1) поддержка не только активности пользователей , но и статистика урл-ов
2) поддержка новых алгоритмов/комманд для расчета.
я ишу способ сделать такую обьектную модель что бы можно было легко расширять / добавлять новые требования.

Конкретно по Visitor паттерну.
1) У меня на вход приходит тип данных , а в вашем примере вы прогодитесь циклом по всем типам (for(DataVisitor command : commands)), как можно переделать использование что -бы не переберать все типы.
2) Возможно ли используя Visitor паттерн поддерживать порядок выполнения комманд для данного типа данных и возможно ли организовать (не для всех случаев) , что результат алгоритма/комманды А это будет входные данные для комманды В для одного и того же типа данных.

Заранее спасибо.
Re[11]: подскажите подходяший шаблон.
От: . Великобритания  
Дата: 26.08.13 15:14
Оценка: 3 (1)
Здравствуйте, RobinHood, Вы писали:

RH>Более конкретно на счет моей задачи.

RH> 1)У меня есть пользователи -- это тип данных.
Т.е. тип данных всего один? Визитор интересен в случае если типов много.

RH> 2)Мне нужно расчитывать активность пользователей по различным критериям

RH> Расчеты ведутся в для различных временных промежутков: 1минута , 10минут , 30мин , 2часа , 1день .....
А что общего в этих расчётах? Что входные данные? Что выходные?
Короче. Начни с юнит-теста — накидай кусок кода который ты хочешь видеть, как использовать.
А там посмотрим каким наиболее простым и эффективным способом решить.

RH> Начаньные требования к системе:

RH> Расчет активности пользователя — (различные статистические алгоритмы) зависит от временных промежутков -- Комманды.
RH>Т.е для 1минуты будет алгоритм А , для 2 часов будет алгоритм Б.
Как нужный алгоритм выбирается?

RH> 3) алгоритмов расчета активности для одного и того же временного промежутка может быть несколько:

RH> для промежутка 10минут может пременятся алгоритм А и затем над результатом Алгоритм В. ==> порядок алгоритмов -- команд важен, и также есть случаи что результат одного алгоритма будет входными данными для другого.
И как этот порядок задаваться должен? Компилятором? Во время запуска приложеня на основе конфигов|бд? Юзер мышкой квадратики щёлкает и соединяет их?

RH>Учитывая что система на ранней стадии мне меняют/добавляют условия очень часто:

RH> Например:
RH> 1) поддержка не только активности пользователей , но и статистика урл-ов
Т.е. второй тип данных? А насколько общий алгоритм для обработки пользователей и урлов?

RH> 2) поддержка новых алгоритмов/комманд для расчета.

RH>я ишу способ сделать такую обьектную модель что бы можно было легко расширять / добавлять новые требования.
TDD. KISS. DRY. YAGNI.

RH>Конкретно по Visitor паттерну.

RH> 1) У меня на вход приходит тип данных , а в вашем примере вы прогодитесь циклом по всем типам (for(DataVisitor command : commands)), как можно переделать использование что -бы не переберать все типы.
Циклы тут причём? Суть такая, что если у тебя есть переменная типа DataVisitor (т.е. инстанс любой команды) и DataType (инстанс какого-то типа данных), то вызовется определённый метод. Т.е. как бы задаётся компилятором проверяемая матрица типов команд и данных.
Или по другому объясню. При вызове метода у объекта класса во время выполнения происходит процедура определения метода, который на самом деле должен быть вызван (так как для объектов разных подклассов эти методы могут быть переопределены), которая называется "одиночная диспетчеризация". Одиночная потому что для определения метода, который будет вызван, используется только один аргумент (неявный this).
Часто возникает необходимость в двойной диспетчеризации — когда для определения того, какой код будет выполнен, нужно учитывать два параметра. Общее описание такой ситуации — когда есть набор некоторых сущностей и набор операций над ними. И первые должны быть максимально независимы вторых. То есть в идеале сущности над которыми производятся операции не должны ничего знать о этих операциях. Для решения этой задачи в рамка ООП был сформулирован шаблон проектирования Visitor (Посетитель).
Отсюда

RH> 2) Возможно ли используя Visitor паттерн поддерживать порядок выполнения комманд для данного типа данных и возможно ли организовать (не для всех случаев) , что результат алгоритма/комманды А это будет входные данные для комманды В для одного и того же типа данных.

Задаёшь список команд как в моём примере.
Насчёт входов-выходов вряд ли. Это скорее всего проще всего сделать тупым кодом, связываемым IoC. Или я не понял что ты хочешь. Показывай пример.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.