Re: Историчность методов
От: Oyster Украина https://github.com/devoyster
Дата: 21.04.05 14:27
Оценка: 1 (1) +1
Здравствуйте, valmond, Вы писали:

V>Подскажите

V>Можно ли каким-то более менее красивым способом устроить историчность реализаций метода.

V>Практическая проблема в том, что для расчета в частности налогов время от времени меняется алгоритм. И необходимо "помнить" о всех версиях и для нужного интервала в прошлом использовать нужную реализацию.


Пиши отдельную реализацию для каждого нового алгоритма. Пусть у всех будет общий интерфейс. Создай менеджер, который будет возвращать (использовать) необходимую реализацию в зависимости от временного интервала.

Как мапить интервал на реализацию... ну, по-моему атрибуты тебе помогут
Re[8]: Историчность методов
От: Oyster Украина https://github.com/devoyster
Дата: 22.04.05 12:54
Оценка: 12 (1)
Здравствуйте, valmond, Вы писали:

V>Зд

O>>Работает, конечно... и получаем тучу hard-coded if-ов или case-ов... вот затем и reflection.

V>Вот именно. Как сделать с кейсами и так понятно. Но уж очень не хочется.


Ок. Тогда простой пример, разбирайся (я его не компилил, но должен работать; в любом случае идея понятна):

// Твой интерфейс
interface IValueCalculator
{
    int CalculateValue();
}

// Реализации. На каждую нацеплен твой атрибут
[Year(2004)]
class OneCalculator : IValueCalculator
{
    public int CalculateValue()
    {
        return 1;
    }
}

[Year(2005)]
class TwoCalculator : IValueCalculator
{
    public int CalculateValue()
    {
        return 2;
    }
}

// Определение своего атрибута
class YearAttribute : Attribute
{
    int _year;
    
    public YearAttribute(int year)
    {
        _year = year;
    }
    
    public int Year {
        get { return _year; }
    }
}

// Определение фабрики
public class CalculatorFactory
{
    static Hashtable _calculatorsHash;
    
    static CalculatorFactory()
    {
        // В статическом конструкторе собираем все типы,
        // реализующие IValueCalculator и имеющие YearAttribute
        _calculatorsHash = new Hashtable();
        
        // Обходим все типы сборки
        Type[] assemblyTypes = Assembly.GetExecutingAssembly().GetTypes();
        for (int i = 0; i < assemblyTypes.Length; ++i) {
            Type type = assemblyTypes[i];
            // Проверяем, реализует ли тип IValueCalculator
            if (typeof(IValueCalculator).IsAssignableFrom(type)) {
                // Проверяем, есть ли у типа YearAttribute
                YearAttribute attribute = (YearAttribute)Attribute.GetCustomAttribute(type, typeof(YearAttribute));
                if (attribute != null) {
                    // Сохраняем тип в хэш (а потом будем создавать)
                    _calculatorsHash[attribute.Year] = type;
                }
            }
        }
    }
    
    static public IValueCalculator GetCalculator(int year)
    {
        Type calculatorType = (Type)_calculatorsHash[year];
        if (calculatorType == null) return null;
        
        // Создаём и возвращаем instance нужного калькулятора
        return Activator.CreateInstance(calculatorType);
    }
}
Re: Историчность методов
От: shapkin Великобритания  
Дата: 22.04.05 07:18
Оценка: 1 (1)
Здравствуйте, valmond, Вы писали:

V>Подскажите

V>Можно ли каким-то более менее красивым способом устроить историчность реализаций метода.

V>Практическая проблема в том, что для расчета в частности налогов время от времени меняется алгоритм. И необходимо "помнить" о всех версиях и для нужного интервала в прошлом использовать нужную реализацию.


Попробоуй применить паттерн Strategy.
Re[6]: Историчность методов
От: Oyster Украина https://github.com/devoyster
Дата: 22.04.05 12:15
Оценка: +1
Здравствуйте, Corwin_XX, Вы писали:

C_X>Я не совсем понимаю, зачем здесь рефлексия. Возможно, я не донца понял суть проблемы.


C_X>Алгоритм — это функция. Может быть функция значением переменной? Может! Я бы использовал делегаты.


Работает, конечно... и получаем тучу hard-coded if-ов или case-ов... вот затем и reflection.
Историчность методов
От: valmond Россия http://blogs.technet.com/valmond/
Дата: 21.04.05 14:19
Оценка:
Подскажите
Можно ли каким-то более менее красивым способом устроить историчность реализаций метода.

Практическая проблема в том, что для расчета в частности налогов время от времени меняется алгоритм. И необходимо "помнить" о всех версиях и для нужного интервала в прошлом использовать нужную реализацию.

22.04.05 23:15: Перенесено модератором из '.NET' — AndrewVK
Заметки — SharePoint & InfoPath
http://blogs.technet.com/valmond/
Re[2]: Историчность методов
От: valmond Россия http://blogs.technet.com/valmond/
Дата: 22.04.05 05:07
Оценка:
O>Пиши отдельную реализацию для каждого нового алгоритма. Пусть у всех будет общий интерфейс. Создай менеджер, который будет возвращать (использовать) необходимую реализацию в зависимости от временного интервала.

Т.е. это примерно фабричный метод получается?

O>Как мапить интервал на реализацию... ну, по-моему атрибуты тебе помогут


ну я тоже сразу о них подумал. Может подскажешь чуть чуть еще? Никогда свои аттрибуты толком не использовал. Логику их работы не до конца понимаю.
Заметки — SharePoint & InfoPath
http://blogs.technet.com/valmond/
Re: Историчность методов
От: valmond Россия http://blogs.technet.com/valmond/
Дата: 22.04.05 05:16
Оценка:
Задача, вроде бы, стандартная для бухгалтерии.
Какие есть решения, пережившие не одно изменение законодательства?
Заметки — SharePoint & InfoPath
http://blogs.technet.com/valmond/
Re[2]: Историчность методов
От: valmond Россия http://blogs.technet.com/valmond/
Дата: 22.04.05 09:30
Оценка:
S>Попробоуй применить паттерн Strategy.

Ок, согласен.
Но каким образом определять какую именно стратегию применять?
кроме case-ов какие-то варианты могут быть?
Заметки — SharePoint & InfoPath
http://blogs.technet.com/valmond/
Re[3]: Историчность методов
От: GarryIV  
Дата: 22.04.05 09:43
Оценка:
Hello, valmond!


S>> Попробоуй применить паттерн

S>> [url=http://www.dofactory.com/Patterns/PatternStrategy.aspx]Strategy[/u
S>> rl].

v> Ок, согласен.

v> Но каким образом определять какую именно стратегию применять?
v> кроме case-ов какие-то варианты могут быть?

Можно составить табличку Дата начала\Дата конца -> ConcreteStrategy и юзать ее. Табличку можно держать в БД, конфиге или прям в коде набить.
Posted via RSDN NNTP Server 1.9
WBR, Igor Evgrafov
Re[4]: Историчность методов
От: valmond Россия http://blogs.technet.com/valmond/
Дата: 22.04.05 09:50
Оценка:
GIV>Можно составить табличку Дата начала\Дата конца -> ConcreteStrategy и юзать ее. Табличку можно держать в БД, конфиге или прям в коде набить.

Угу, вариант. А создавать конкретную стратегию через рефлексию. Так?
Заметки — SharePoint & InfoPath
http://blogs.technet.com/valmond/
Re[5]: Историчность методов
От: GarryIV  
Дата: 22.04.05 10:27
Оценка:
Hello, valmond!


GIV>> Можно составить табличку Дата начала\Дата конца -> ConcreteStrategy и

GIV>> юзать ее. Табличку можно держать в БД, конфиге или прям в коде
GIV>> набить.

v> Угу, вариант. А создавать конкретную стратегию через рефлексию. Так?


Да. В конечном счете через рефлексию.
Posted via RSDN NNTP Server 1.9
WBR, Igor Evgrafov
Re[5]: Историчность методов
От: Аноним  
Дата: 22.04.05 11:38
Оценка:
Я не совсем понимаю, зачем здесь рефлексия. Возможно, я не донца понял суть проблемы.

Алгоритм — это функция. Может быть функция значением переменной? Может! Я бы использовал делегаты.

 delegate double GetNalogDelegate(double sum);
 private static double GetNalog10(double sum)
 {
  return sum * 0.1;
 }
 private static double GetNalog20(double sum)
 {
  return sum * 0.2;
 }
 
 private static void TestDelegate()
 {
  double nalog1 = GetNalog(1000.0, new DateTime(1990, 1, 1));
  double nalog2 = GetNalog(1000.0, new DateTime(2000, 1, 1));
  Console.WriteLine("{0}; {1}", nalog1, nalog2);
 }
 private static double GetNalog(double sum, DateTime date)
 {
  GetNalogDelegate getNalog;
  if(date.Year < 2000)
  {
   getNalog = new GetNalogDelegate(GetNalog20);
  }
  else
  {
   getNalog = new GetNalogDelegate(GetNalog10);
  }
  return getNalog(sum);
 }





данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[5]: Историчность методов
От: Аноним  
Дата: 22.04.05 11:39
Оценка:
Опечатка:
"не донца" = "не до конца"

з.ы. Код проверил — работает.


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[7]: Историчность методов
От: valmond Россия http://blogs.technet.com/valmond/
Дата: 22.04.05 12:35
Оценка:
Зд
O>Работает, конечно... и получаем тучу hard-coded if-ов или case-ов... вот затем и reflection.

Вот именно. Как сделать с кейсами и так понятно. Но уж очень не хочется.
Заметки — SharePoint & InfoPath
http://blogs.technet.com/valmond/
Re[7]: Историчность методов
От: Аноним  
Дата: 22.04.05 12:51
Оценка:
Oyster

Работает, конечно... и получаем тучу hard-coded if-ов или case-ов... вот затем и reflection.

Не понимаю, а чем отличается моё:
"напиши метод, который будет возвращать нужный делегат в зависимости от временного интервала"
от Вашего:
"Создай менеджер, который будет возвращать (использовать) необходимую реализацию в зависимости от временного интервала."

(с точки зрения количества if'ов)



данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[7]: Историчность методов
От: Аноним  
Дата: 22.04.05 12:55
Оценка:
Чем Вам мешают эти кейсы? Спрячьте их в одельный класс и открывайте его код только чтобы добавить ещё один кейс, когда очередной раз изменится законодательство.



данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[9]: PS
От: Oyster Украина https://github.com/devoyster
Дата: 22.04.05 12:59
Оценка:
По возможности я стараюсь не использовать reflection (а если и использую, то стараюсь минимизировать временные затраты — кеширую, например). Например, если у тебя всего 3 реализации, то хватит и if/switch. Но если их много или в будущем будут ещё добавляться, рефлекшн с атрибутами могут стать хорошим подспорьем. Например, при создании новой реализации достаточно будет написать класс, реализующий интерфейс, и навесить на него атрибут (не придётся лезть в дебри какого-нить ужасного switch-а ).
Re[10]: PS
От: valmond Россия http://blogs.technet.com/valmond/
Дата: 22.04.05 13:02
Оценка:
Здравствуйте, Oyster, Вы писали:

O>По возможности я стараюсь не использовать reflection (а если и использую, то стараюсь минимизировать временные затраты — кеширую, например). Например, если у тебя всего 3 реализации, то хватит и if/switch. Но если их много или в будущем будут ещё добавляться, рефлекшн с атрибутами могут стать хорошим подспорьем. Например, при создании новой реализации достаточно будет написать класс, реализующий интерфейс, и навесить на него атрибут (не придётся лезть в дебри какого-нить ужасного switch-а ).


Мне кажется тут тот случай когда аккуратность кода стоит выше чем возможные потери на рефлексию.
С рефлексией я смогу разнести все классы по разным файлам, например. И вообще могу забыть о фабрике и о всех старых реализациях в момент добавления новой.

В общем это то что надо.Спасибо.
Заметки — SharePoint & InfoPath
http://blogs.technet.com/valmond/
Re[10]: PS
От: Аноним  
Дата: 22.04.05 13:10
Оценка:
С рефлексией можно и через базу конфигурить вызов нужной реализации.
-----
Нулевое оформления постов благодаря Opere.


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[8]: Историчность методов
От: Oyster Украина https://github.com/devoyster
Дата: 22.04.05 13:14
Оценка:
Здравствуйте, Corwin_XX, Вы писали:

C_X>Oyster


C_X>Работает, конечно... и получаем тучу hard-coded if-ов или case-ов... вот затем и reflection.

C_X>

C_X>Не понимаю, а чем отличается моё:
C_X>"напиши метод, который будет возвращать нужный делегат в зависимости от временного интервала"
C_X>от Вашего:
C_X>"Создай менеджер, который будет возвращать (использовать) необходимую реализацию в зависимости от временного интервала."

C_X>(с точки зрения количества if'ов)


Ничем. См. мой ответ
Автор: Oyster
Дата: 22.04.05
— я говорил об этом, когда имел в виду использование reflection.
Re[8]: Историчность методов
От: Oyster Украина https://github.com/devoyster
Дата: 22.04.05 13:17
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Чем Вам мешают эти кейсы? Спрячьте их в одельный класс и открывайте его код только чтобы добавить ещё один кейс, когда очередной раз изменится законодательство.


Иногда законодательство меняется слишком часто.
Re[10]: PS
От: Аноним  
Дата: 22.04.05 13:18
Оценка:
valmond

С рефлексией я смогу разнести все классы по разным файлам, например.

А без рефлексии этого сделать нельзя?

И вообще могу забыть о фабрике и о всех старых реализациях в момент добавления новой.

Этого я, вообще, не понял.



данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[8]: Историчность методов
От: Аноним  
Дата: 22.04.05 13:21
Оценка:
Oyster

Я не против использования атрибутов. Я не понимаю, зачем нужно:
Activator.CreateInstance(calculatorType)




данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[8]: Историчность методов
От: valmond Россия http://blogs.technet.com/valmond/
Дата: 22.04.05 13:29
Оценка:
Здравствуйте, Corwin_XX, Вы писали:

C_X>Чем Вам мешают эти кейсы? Спрячьте их в одельный класс и открывайте его код только чтобы добавить ещё один кейс, когда очередной раз изменится законодательство.



Вы наверное не видели во что вырастают кейсы через некоторое время.
Я увидел и волосы встали дыбом.
Заметки — SharePoint & InfoPath
http://blogs.technet.com/valmond/
Re[9]: Историчность методов
От: Oyster Украина https://github.com/devoyster
Дата: 22.04.05 13:48
Оценка:
Здравствуйте, Corwin_XX, Вы писали:

C_X>Oyster


C_X>Я не против использования атрибутов. Я не понимаю, зачем нужно:

C_X>Activator.CreateInstance(calculatorType)

Чтобы создать инстанс по типу в случае если нам нужен новый инстанс каждый раз (да, бывает и так). На самом деле можно в Hashtable и instance держать — ведь я написал всего лишь пример...
Re[8]: Историчность методов
От: Аноним  
Дата: 22.04.05 14:05
Оценка:
valmond

На самом деле вопрос разбивается на три вопроса.


1. Использовать Activator.CreateInstance или использовать delegate

Единственная разница в том, что в первом случае при изменении законодательства придётся добавлять новый класс, а во втором случае — новый метод. При желании, можно каждый раз выделять этот метод в отдельный класс. Тогда с точки зрения изменений в коде при изменениях законодательства не будет никакой разницы.

Зачем использовать Activator.CreateInstance, если можно обойтись без него?
Обратите внимание, на количество Case'ов это никак не повлияет.


2. Использовать атрибуты или не использовать.

Единственная разница в том, что в первом случае при изменении законодательства нужно будет добавлять перед классом/методом строку:
[Year(2004)]
Во втором случае нужно будет добавить в некий метод строку:
_calculatorsHash[2004] = new GetNalogDelegate(GetNalog2004);

Не вижу большой разницы. (Ведь в том методе нет ничего кроме таких вот строчек — запутаться негде.


3. Использовать Hashtable или Switch

Разница в добавляемой в тот самый метод (см. пункт 2) строке. Во втором случае она будет выглядеть так:
case 2004:
res = new GetNalogDelegate(GetNalog2004);
break;

Опять же не вижу принципиальной разницы. Ведь этот метод содержит один единственный Switch и ничего более.
(Фактически, он делает то же самое, что и Hashtable — возвращает значение по индексу.)




данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[8]: Историчность методов
От: Аноним  
Дата: 22.04.05 14:05
Оценка:
"Вы наверное не видели во что вырастают кейсы через некоторое время."
Они еще и делиться в разные файлы могут.
-----
Нулевое оформления постов благодаря Opere.


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[9]: Историчность методов
От: Oyster Украина https://github.com/devoyster
Дата: 22.04.05 14:24
Оценка:
Здравствуйте, Corwin_XX, Вы писали:

[... поскипано с особым цинизмом ...]

Разница в том, что при указанном мной подходе тебе придётся модифицировать только 1 класс, а это большое преимущество (предщставь себе 2000 классов. Говорите — нереально? А вот и нет...).

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

В общем, я привёл пример реализации. Заметил, что не всегда имеет смысл так извращаться и использовать атрибуты/рефлекшн. И согласен, что иногда старый добрый switch с делегатами будет проще и эффективнее. Засим считаю тему закрытой.
Re: Историчность методов
От: nayato Россия  
Дата: 24.04.05 18:48
Оценка:
Здравствуйте, valmond, Вы писали:

V>Подскажите

V>Можно ли каким-то более менее красивым способом устроить историчность реализаций метода.

V>Практическая проблема в том, что для расчета в частности налогов время от времени меняется алгоритм. И необходимо "помнить" о всех версиях и для нужного интервала в прошлом использовать нужную реализацию.


Решение этой проблемы в общем случае — "динамический полиморфизм". У нас даже докторскую из этого вроде делать собираются. Кандидатская уже по крайней мере есть
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Re[2]: Историчность методов
От: valmond Россия http://blogs.technet.com/valmond/
Дата: 25.04.05 05:10
Оценка:
N>Решение этой проблемы в общем случае — "динамический полиморфизм". У нас даже докторскую из этого вроде делать собираются. Кандидатская уже по крайней мере есть

Интересное, а практическое применение на языках .Net у этих знаний есть?
Заметки — SharePoint & InfoPath
http://blogs.technet.com/valmond/
Re[3]: Историчность методов
От: nayato Россия  
Дата: 25.04.05 14:29
Оценка:
Здравствуйте, valmond, Вы писали:

V>Интересное, а практическое применение на языках .Net у этих знаний есть?


Мне тоже интересно... Они .НЕТ не практикуют. Там все на уровне длл да хранимых процедур.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.