Я часто нахожу себя пишущим функции, которые выглядят так, потому что они позволяют мне легко смоделировать доступ к данным, и все же предоставляют подпись, которая принимает параметры, определяющие, к каким данным обращаться.
public static string GetFormattedRate(
Func<string, RateType>> getRate,
string rateKey)
{
var rate = getRate(rateKey);
var formattedRate = rate.DollarsPerMonth.ToString("C0");
return formattedRate;
}
Или
public static string GetFormattedRate(
Func<RateType, string> formatRate,
Func<string, RateType>> getRate,
string rateKey)
{
var rate = getRate(rateKey);
var formattedRate = formatRate(rate);
return formattedRate;
}
Тогда я использую что-то вроде этого:
using FormatterModule;
public static Main()
{
var getRate = GetRateFunc(connectionStr);
var formattedRate = GetFormattedRate(getRate, rateType);
// or alternatively
var formattedRate = GetFormattedRate(getRate, FormatterModule.FormatRate, rateKey);
System.PrintLn(formattedRate);
}
Это обычная практика? Я чувствую, что должен делать что-то более похожее
public static string GetFormattedRate(
Func<RateType> getRate())
{
var rate = getRate();
return rate.DollarsPerMonth.ToString("C0");
}
Но, похоже, это не очень хорошо работает, потому что мне нужно было бы создать новую функцию для передачи в метод для каждого типа ставки.
Иногда я чувствую, что должен делать
public static string GetFormattedRate(RateType rate)
{
return rate.DollarsPerMonth.ToString("C0");
}
Но это, кажется, убирает любую выборку и возможность повторного использования формата. Всякий раз, когда я хочу получить и отформатировать, я должен написать две строки, одну для извлечения и одну для форматирования.
Что мне не хватает в функциональном программировании? Это правильный способ сделать это, или есть лучший шаблон, который легко поддерживать и использовать?
источник
GetFormattedRate()
принимать скорость форматирования в качестве параметра, а не принимать функцию, которая возвращает скорость для форматирования в качестве параметра?closures
где вы передаете сам параметр в функцию, которая, в свою очередь, дает вам функцию, ссылающуюся на этот конкретный параметр. Эта «настроенная» функция будет передана в качестве параметра функции, которая ее использует.Ответы:
Если вы будете делать это достаточно долго, вы в конечном итоге будете писать эту функцию снова и снова:
Поздравляем, вы придумали композицию функций .
Подобные функции Wrapper не имеют особого смысла, когда они специализированы для одного типа. Однако, если вы введете некоторые переменные типа и пропустите входной параметр, то ваше определение GetFormattedRate будет выглядеть так:
Как бы то ни было, то, что вы делаете, имеет мало смысла. Это не универсальный, поэтому вы должны дублировать этот код повсюду. Это усложняет ваш код, потому что теперь ваш код должен собрать все, что ему нужно, из тысячи крошечных функций самостоятельно. Однако ваше сердце находится в нужном месте: вам просто нужно привыкнуть к использованию этих видов универсальных функций высшего порядка для объединения вещей. Или использовать хорошую старую моды лямбду превратить
Func<A, B>
иA
вFunc<B>
.Не повторяйся.
источник
FormatRate(GetRate(rateKey))
.GetFormattedRate
теперь сможет использовать напрямую.Func<Func<A, B>, C>
); это означает, что вам нужна только одна функция Compose, которая работает для любой функции. Тем не менее, вы можете достаточно хорошо работать с функциями C #, просто используя замыкания - вместо того, чтобы передаватьFunc<rateKey, rateType>
, вы действительно нуждаетесь в немFunc<rateType>
, а когда передаете функцию, вы создаете ее следующим образом() => GetRate(rateKey)
. Дело в том, что вы не выставляете аргументы, которые не интересуют целевой функции.Compose
функция действительно полезна только в том случае, если вам необходимо поGetRate
какой-то причине отложить выполнение , например, если вы хотите перейтиCompose(FormatRate, GetRate)
к функции, которая обеспечивает скорость по своему выбору, например, применить ее к каждому элементу в список.Нет абсолютно никакой причины передавать функцию и ее параметры только для того, чтобы затем вызывать ее с этими параметрами. В самом деле, в вашем случае нет никаких оснований , чтобы передать функцию вообще . Вызывающая сторона может просто вызвать саму функцию и передать результат.
Подумайте об этом - вместо использования:
почему бы просто не использовать:
?
Наряду с уменьшением ненужного кода это также уменьшает сцепление - если вы хотите изменить способ получения скорости (скажем, если
getRate
теперь нужно два аргумента), вам не нужно менятьGetFormattedRate
.Точно так же нет причин писать
GetFormattedRate(formatRate, getRate, rateKey)
вместо того, чтобы писатьformatRate(getRate(rateKey))
.Не переусердствуйте.
источник
formatRate
должно быть сопоставлено со скоростями, которые должны быть отформатированы).Если вам абсолютно необходимо передать функцию в функцию, потому что она передает дополнительный аргумент или вызывает ее в цикле, вы можете вместо этого передать лямбду:
Лямбда свяжет аргументы, о которых функция не знает, и скроет, что они даже существуют.
источник
Разве это не то, что вы хотите?
И затем назовите это так:
Если вам нужен метод, который может вести себя по-разному в объектно-ориентированном языке, таком как C #, обычный способ сделать это - вызвать метод абстрактным методом. Если у вас нет конкретной причины сделать это по-другому, вы должны сделать это таким образом.
Похоже ли это на хорошее решение или есть недостатки?
источник
GetFormattedRate
метод и просто вызватьIRateFormatter.FormatRate(rate)
). Однако основная концепция верна, и я думаю, что OP тоже должен реализовывать свой код полиморфно, если ему нужно несколько методов форматирования.