Как я уменьшаю шаблон “использования” для новых форм?

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

const deepProp = (o = {}, props = []) =>
  props.reduce((acc = {}, p) => acc[p], o)

Теперь без такого большого шума -

sortBy = (keys, isReverse = false) =>
  this.setState ({
    files: // without mutating the previous state!
      [...this.state.files].sort((a,b) => {
        const valueA = deepProp(a, keys) || ''
        const valueB = deepProp(b, keys) || ''
        return isReverse
          ? valueA.localeCompare(valueB)
          : valueB.localeCompare(valueA)
      })
  })

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

sortBy = (comparator = asc) =>
  this.setState
    ( { files:
          isort
            ( contramap
                ( comparator
                , generalFileId
                )
            , this.state.files
            )
      }
    )

Ваш вопрос ставит нас перед изучением двух мощных функциональных концепций; мы будем использовать их, чтобы ответить на вопрос -

  1. Монады
  2. Контравариантные функторы

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

Ваш вопрос, в частности, говорит, что вы не используете внешний пакет прямо сейчас, но сейчас самое подходящее время для его получения. Давайте кратко рассмотрим пакет data.maybe -

Структура для значений, которые могут отсутствовать, или для вычислений, которые могут не работать. Maybe(a) явно моделирует эффекты, неявные в типах Nullable, таким образом, не имеет никаких проблем, связанных с использованием null или undefined - как NullPointerException или TypeError.

blockquote>

Звучит как хорошая подгонка. Мы начнем с написания функции safeProp, которая принимает объект и строку свойства в качестве входных данных. Интуитивно понятно, что safeProp безопасно возвращает свойство p объекта o -

const { Nothing, fromNullable } =
  require ('data.maybe')

const safeProp = (o = {}, p = '') =>

  // if o is an object
  Object (o) === o

    // access property p on object o, wrapping the result in a Maybe
    ? fromNullable (o[p])

    // otherwise o is not an object, return Nothing
    : Nothing ()

Вместо простого возврата o[p], который мог бы быть нулевое или неопределенное значение, мы вернемся Может быть , которое поможет нам в обработке результата -

const generalFileId = (o = {}) =>

  // access the general property
  safeProp (o, 'general')

    // if it exists, access the fileId property on the child
    .chain (child => safeProp (child, 'fileId'))

    // get the result if valid, otherwise return empty string
    .getOrElse ('') 

Теперь у нас есть функция, которая может принимать объекты различной сложности и [1171 ] гарантирует результат, который нас интересует -

console .log
  ( generalFileId ({ general: { fileId: 'a' } })  // 'a'
  , generalFileId ({ general: { fileId: 'b' } })  // 'b'
  , generalFileId ({ general: 'x' })              // ''
  , generalFileId ({ a: 'x '})                    // ''
  , generalFileId ({ general: { err: 'x' } })     // ''
  , generalFileId ({})                            // ''
  )

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

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

Может возникнуть вопрос, как работает Array? Как он вычисляет или корректирует свойство length, когда элемент добавляется или удаляется из массива? Как функция map или filter создает новый новый массив ? Если вы никогда не задумывались об этом раньше, это нормально! Массив является удобным модулем, потому что он устраняет эти проблемы из головы программиста; это просто работает как рекламируется .

Это применимо независимо от того, предоставляется ли модуль JavaScript, третьей стороной, например, из npm, или если вы написали модуль самостоятельно. Если Array не существует, мы могли бы реализовать его как нашу собственную структуру данных с эквивалентными удобствами. Пользователи нашего модуля получают полезные функциональные возможности без , вносящие дополнительную сложность. А-ха наступает момент, когда вы понимаете, что программист является его / ее собственным пользователем: когда вы сталкиваетесь с трудной проблемой, напишите модуль, чтобы избавиться от оков сложности. Придумайте ваше собственное удобство!

Мы покажем базовую реализацию Maybe позже в ответе, но сейчас нам просто нужно закончить сортировку ...


Начнем с двух основных компараторов, asc для сортировки по возрастанию, и desc для сортировки по убыванию -

const asc = (a, b) =>
  a .localeCompare (b)

const desc = (a, b) =>
  asc (a, b) * -1

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

const isort = (compare = asc, xs = []) =>
  xs
    .slice (0)      // clone
    .sort (compare) // then sort

И, конечно, a и b иногда являются сложными объектами, поэтому случай, когда мы не можем напрямую позвонить asc или desc. Ниже contramap преобразует наши данные с помощью одной функции g, перед тем, как передаст данные другой функции, f -

const contramap = (f, g) =>
  (a, b) => f (g (a), g (b))

const files =
  [ { general: { fileId: 'e' } }
  , { general: { fileId: 'b' } }
  , { general: { fileId: 'd' } }
  , { general: { fileId: 'c' } }
  , { general: { fileId: 'a' } }
  ]

isort
  ( contramap (asc, generalFileId) // ascending comparator
  , files
  )

// [ { general: { fileId: 'a' } }
// , { general: { fileId: 'b' } }
// , { general: { fileId: 'c' } }
// , { general: { fileId: 'd' } }
// , { general: { fileId: 'e' } }
// ]

с помощью другого компаратора desc. ], мы можем видеть работу сортировки в другом направлении -

isort
  ( contramap (desc, generalFileId) // descending comparator
  , files 
  )

// [ { general: { fileId: 'e' } }
// , { general: { fileId: 'd' } }
// , { general: { fileId: 'c' } }
// , { general: { fileId: 'b' } }
// , { general: { fileId: 'a' } }
// ]

Теперь, чтобы написать метод для вашего компонента React, sortBy. Метод существенно сокращен до this.setState({ files: t (this.state.files) }), где t - это неизменное преобразование состояния вашей программы. Это хорошо, потому что сложность исключается из ваших компонентов, где тестирование затруднено, и вместо этого находится в универсальных модулях, которые легко тестировать -

sortBy = (reverse = true) =>
  this.setState
    ( { files:
          isort
            ( contramap
                ( reverse ? desc : asc
                , generalFileId
                )
            , this.state.files
            )
      }
    )

При этом используется логический переключатель как в вашем первоначальном вопросе, но поскольку React включает функциональный шаблон, я думаю, что он будет еще лучше в качестве функции более высокого порядка -

sortBy = (comparator = asc) =>
  this.setState
    ( { files:
          isort
            ( contramap
                ( comparator
                , generalFileId
                )
            , this.state.files
            )
      }
    )

Если не требуется гарантированное доступ к вложенному свойству чтобы быть general и fileId, мы можем сделать универсальную функцию, которая принимает список свойств и может искать вложенное свойство любой глубины -

const deepProp = (o = {}, props = []) =>
  props .reduce
    ( (acc, p) => // for each p, safely lookup p on child
        acc .chain (child => safeProp (child, p))
    , fromNullable (o) // init with Maybe o
    )

const generalFileId = (o = {}) =>
  deepProp (o, [ 'general', 'fileId' ]) // using deepProp
    .getOrElse ('')

const fooBarQux = (o = {}) =>
  deepProp (o, [ 'foo', 'bar', 'qux' ]) // any number of nested props
    .getOrElse (0)                      // customizable default

console.log
  ( generalFileId ({ general: { fileId: 'a' } } ) // 'a'
  , generalFileId ({})                            // ''
  , fooBarQux ({ foo: { bar: { qux: 1 } } } )     // 1
  , fooBarQux ({ foo: { bar: 2 } })               // 0
  , fooBarQux ({})                                // 0
  )

Выше мы используем пакет data.maybe, который дает нам возможность работать с потенциальными значениями . Модуль экспортирует функции для преобразования обычных значений в Maybe и наоборот, а также множество полезных операций, применимых к потенциальным значениям. Однако ничто не заставляет вас использовать именно эту реализацию. Концепция достаточно проста, чтобы вы могли реализовать fromNullable, Just и Nothing в виде пары дюжин строк, которые мы увидим позже в этом ответе -

Запустите полную демонстрацию ниже на ] repl.it

const { Just, Nothing, fromNullable } =
  require ('data.maybe')

const safeProp = (o = {}, p = '') =>
  Object (o) === o
    ? fromNullable (o[p])
    : Nothing ()

const generalFileId = (o = {}) =>
  safeProp (o, 'general')
    .chain (child => safeProp (child, 'fileId'))
    .getOrElse ('')

// ----------------------------------------------
const asc = (a, b) =>
  a .localeCompare (b)

const desc = (a, b) =>
  asc (a, b) * -1

const contramap = (f, g) =>
  (a, b) => f (g (a), g (b))

const isort = (compare = asc, xs = []) =>
  xs
    .slice (0)
    .sort (compare)

// ----------------------------------------------
const files =
  [ { general: { fileId: 'e' } }
  , { general: { fileId: 'b' } }
  , { general: { fileId: 'd' } }
  , { general: { fileId: 'c' } }
  , { general: { fileId: 'a' } }
  ]

isort
  ( contramap (asc, generalFileId)
  , files
  )

// [ { general: { fileId: 'a' } }
// , { general: { fileId: 'b' } }
// , { general: { fileId: 'c' } }
// , { general: { fileId: 'd' } }
// , { general: { fileId: 'e' } }
// ]

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

Наконец, sortBy реализован как функция высшего порядка, что означает, что мы не ограничены только восходящими и нисходящими сортировками, переключаемыми логическим значением reverse; любой действительный компаратор может быть использован. Это означает, что мы могли бы даже написать специализированный компаратор, который обрабатывает разрывы связей, используя пользовательскую логику, или сравнивает сначала year, затем month, затем day и т. Д .; функции высшего порядка расширяют ваши возможности.


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

// Maybe.js
const None =
  Symbol ()

class Maybe
{ constructor (v)
  { this.value = v }

  chain (f)
  { return this.value == None ? this : f (this.value) }

  getOrElse (v)
  { return this.value === None ? v : this.value }
}

const Nothing = () =>
  new Maybe (None)

const Just = v =>
  new Maybe (v)

const fromNullable = v =>
  v == null
    ? Nothing ()
    : Just (v)

module.exports =
  { Just, Nothing, fromNullable } // note the class is hidden from the user

Тогда мы будем использовать его в нашем модуле. Нам нужно только изменить импорт (require), но все остальное просто работает как есть из-за общедоступного API-интерфейса совпадений нашего модуля -

const { Just, Nothing, fromNullable } =
  require ('./Maybe') // this time, use our own Maybe

const safeProp = (o = {}, p = '') => // nothing changes here
  Object (o) === o
    ? fromNullable (o[p])
    : Nothing ()

const deepProp = (o, props) => // nothing changes here
  props .reduce
    ( (acc, p) =>
        acc .chain (child => safeProp (child, p))
    , fromNullable (o)
    )

// ...

Для получения дополнительной информации о том, как использовать контркарту и, возможно, некоторые неожиданные сюрпризы, пожалуйста, изучите следующие связанные ответы -

  1. мультисортировка с использованием контркарты
  2. рекурсивный поиск с использованием контркарты

11
задан skamradt 18 May 2009 в 22:31
поделиться

4 ответа

Соответствующий ресурс находится в $ (BDS) \ bin \ delphivclide * .bpl и называется "VCLIDECMD"; вы можете извлекать, редактировать и обновлять его с помощью редактора ресурсов по вашему выбору (я рекомендую тот, который включен в Pelles C ).

Для пользователей C ++ Builder файл шаблона - «CPPVCLIDECMD» в bcbvclide * .bpl.

Если вы используете локализованную версию RAD Studio,

13
ответ дан 3 December 2019 в 04:53
поделиться

Вы ничего не сохраняете, удаляя сообщения Windows и Сообщения . Графические и Диалоги могут быть добавлены обратно в зависимости от того, какие компоненты вы добавляете в форму, и в любом случае на них довольно полезно ссылаться. Сомневаюсь, что удаляя их, вы много экономите. Не стесняйтесь удалять вариантов , если вы их не используете (что, я согласен, довольно распространено, если не занимается разработкой COM или DB).

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

Что касается изменения шаблона по умолчанию, я полагаю, что это есть в пакете, который говорит, что если вы спускаетесь с TForm, вы их получите. Скорее всего, вам потребуется изменить файл. PAS и пересоберите пакеты VCL. Много работы с очень небольшой прибылью.

5
ответ дан 3 December 2019 в 04:53
поделиться

Я обычно использую «Uses cleaner», который поставляется с cnPack после завершения проекта, он даст вам список для все неиспользуемые единицы в вашем проекте, потому что обычно при завершении проекта у вас могут быть неиспользуемые единицы большего размера, чем вы упомянули.

5
ответ дан 3 December 2019 в 04:53
поделиться

На самом деле, это меня тоже беспокоило.

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

Dialogs.pas добавляет несколько килобайт, но я часто использую диалоги Delphi VCL вместо диалогов Win API.

Так что я бы сказал, что не особо возиться с ними

0
ответ дан 3 December 2019 в 04:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: