Шаблонный код
Из Википедии, бесплатной энциклопедии
Шаблонный код, boilerplate-код (англ. boilerplate code) — нетворческий программный код, который программисту приходится писать вследствие требований языка программирования, операционной системы, библиотеки подпрограмм, манеры программирования и прочего. Название «шаблонный» говорит, что он повторяется из функции в функцию, из программы в программу с минимальными изменениями. Шаблонными, в числе прочего, будут:
- подключение модулей;
- настройка компилятора и/или системы сборки;
- организация точки входа в программу или подпрограмму;
- код инициализации и выхода.
Например, в простейшем «Hello, world» на Си все строки, кроме собственно printf(...)
, будут шаблонными.
#include <stdio.h> //< шаблонный — подключение модуля int main() //< шаблонный — точка входа { //< шаблонный — точка входа printf("Hello, world!\n"); //< творческий!! return 0; //< шаблонный — выход } //< шаблонный — точка входа
К шаблонному коду близок так называемый bookkeeping code — творческий, но сравнительно простой код, обеспечивающий дополнительные стороны функционирования программы наподобие загрузки-сохранения.
Этимология понятия «boilerplate»[править | править код]
Слово «boilerplate» по-английски означает «котельное железо». Применительно к шаблонному тексту встречается уже в 1950-х. Этимология неясна и определённо происходит из лексикона полиграфистов, основные версии:
- Местные американские газетки подписывались на новости у крупных печатных синдикатов, и те присылали готовые заметки в виде отлитых печатных форм. Эти формы и называли «котельным железом»[1][2].
- Печатные формы, которые нужны были многократно в нескольких выпусках газеты — для газетных шапок, объявлений от постоянных клиентов и т. д. — делали из стали, в то время как основная часть газеты набиралась из свинцового сплава[3].
- Дымогарный котёл требовал сверления множества отверстий, в которые вставляли дымогарные трубы. Для сверления использовали пластины-шаблоны, и написание стандартных объявлений сравнили с шаблонным сверлением отверстий[4][5].
Методы уменьшения количества шаблонного кода[править | править код]
Системы и библиотеки, решающие вопрос[править | править код]
Стандартный код на Java:
public class Book { private String m_ISBN; private String m_Title; private String m_SubTitle; private String m_Autor; public String getISBN() { return m_ISBN; } public void setISBN(String pISBN) { m_ISBN = pISBN; } public String getTitle() { return m_Title; } public void setTitle(String pTitle) { m_Title = pTitle; } public String getSubTitle() { return m_SubTitle; } public void setSubTitle(String pSubTitle) { m_SubTitle = pSubTitle; } public String getAutor() { return m_Autor; } public void setAutor(String pAutor) { m_Autor = pAutor; } }
Аналогичный код на C#…
public class Book { public string ISBN { get; set; } public string Title { get; set; } public string SubTitle { get; set; } public string Autor { get; set; } }
…и на Kotlin
data class Book(var ISBN: String, var Title: String, var SubTitle: String, var Autor: String)
Автогенераторы кода[править | править код]
Например, в системе Qt Widgets код минимальной формы с кнопкой состоит из нескольких файлов, приведём один.
//== FmMain.cpp == #include "FmMain.h" #include "ui_FmMain.h" FmMain::FmMain(QWidget *parent) : QMainWindow(parent) , ui(new Ui::FmMain) { ui->setupUi(this); } FmMain::~FmMain() { delete ui; } void FmMain::on_btDemo_clicked() { ui->btDemo->setText("Demo!!"); //< Только эту строку мы пишем вручную! }
При этом только одну строку программист пишет вручную.
Адекватные настройки по умолчанию[править | править код]
Пример 1. В Qt+MinGW для создания автономной консольной программы под Windows надо сделать:
win32-g++ { QMAKE_CXXFLAGS += -static-libgcc -static-libstdc++ LIBS += -static -lpthread }
Это также считается шаблонным кодом. Поскольку мелкие учебные и экспериментальные программы обычно являются автономными и консольными, возможно, следовало бы добавлять подобный код всегда при создании пустой консольной программы — а разработчик более сложного ПО, использующего чужие динамические библиотеки, просто стирал бы его.
Пример 2. Полный HTML выглядит так:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <title>Test</title> </head> <body> <p>Hello world!</p> </body> </html>
Стандарт WHATWG HTML позволяет опустить html, head и body[6]. Meta charset можно опустить, если HTML пришёл от сервера и в заголовках HTTP есть кодировка. Так что остаётся…
<!DOCTYPE html> <title>Test</title> <p>Hello world!</p>
Препроцессоры[править | править код]
Пример 1. В том же Qt есть две программы, создающие часть Си++-кода формы — метаобъектный компилятор (moc) и компилятор интерфейса (uic).
Пример 2. Создание копии объекта с учётом умных указателей Си++11 выглядит так.
#include <iostream> #include <memory> class Abstract { public: auto clone() const { return std::unique_ptr<Abstract>{ vclone() }; } protected: virtual Abstract* vclone() const = 0; }; class Abstract2 : public Abstract { public: auto clone() const { return std::unique_ptr<Abstract2>{ vclone() }; } protected: virtual Abstract2* vclone() const = 0; }; class Concrete : public Abstract2 { public: auto clone() const { return std::unique_ptr<Concrete>{ vclone() }; } protected: Concrete* vclone() const override { return new Concrete(*this); } }; int main() { Concrete impl; Abstract* a = &impl; std::unique_ptr<Abstract> b = a->clone(); std::unique_ptr<Concrete> c = impl.clone(); return 0; }
Здесь шаблонный код — реализации функций vclone
и clone
.
С препроцессором Си этот код будет выглядеть так, и чем больше классов в иерархии, тем больше выигрыш:
#define IMPL_CLONE_1(Class, Body) \ public: auto clone() const { return std::unique_ptr<Class>{ vclone() }; } \ protected: virtual Class* vclone() const Body #define IMPL_CLONE_ABSTRACT(Class) IMPL_CLONE_1(Class, override = 0;) #define IMPL_CLONE_CONCRETE(Class) IMPL_CLONE_1(Class, override { return new Class(*this); }) class Abstract { IMPL_CLONE_1(Abstract, =0;) }; class Abstract2 : public Abstract { IMPL_CLONE_ABSTRACT(Abstract2) }; class Concrete : public Abstract2 { IMPL_CLONE_CONCRETE(Concrete) };
Метапрограммирование[править | править код]
На Си++ обрезка пробелов (trim) в строках разного типа «на месте» (без выделения памяти) будет выглядеть так:
std::string_view trimSv(std::string_view x) { // Какая-то реализация } std::wstring_view trimSv(std::wstring_view x) { // Похожая реализация }
И то же с метапрограммированием:
namespace detail { template <class Ch, class Traits> std::basic_string_view<Ch, Traits> trimSv(std::basic_string_view<Ch, Traits> x) { // Реализация } } template <class S> inline auto trimSv(const S& x) { return detail::trimSv(static_cast<std::basic_string_view>(x)); }
Код также многословный (вторая функция нужна, чтобы под шаблон подходил не только std::string_view, но и близкие к нему типы std::string и const char*), но как минимум без повторов.
Примечания[править | править код]
- ↑ Источник . Дата обращения: 9 февраля 2022. Архивировано 9 февраля 2022 года.
- ↑ Boilerplate Definition & Meaning — Merriam-Webster . Дата обращения: 9 февраля 2022. Архивировано 14 декабря 2021 года.
- ↑ Why is it «Boilerplate text?» | Mental Floss
- ↑ What is the origin of the term 'boilerplate'? — Quora
- ↑ Boilerplate Definition . Дата обращения: 9 февраля 2022. Архивировано 9 февраля 2022 года.
- ↑ HTML Standard . Дата обращения: 12 ноября 2022. Архивировано 26 сентября 2021 года.