Menu
Coddy logo textTech

Цепочки вызовов методов

Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy. Урок 81 из 107.

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

key — это возврат указателя на структуру из каждого метода:

type Query struct {
    table   string
    columns []string
    where   string
    limit   int
}

func (q *Query) Select(cols ...string) *Query {
    q.columns = cols
    return q
}

func (q *Query) From(table string) *Query {
    q.table = table
    return q
}

func (q *Query) Where(condition string) *Query {
    q.where = condition
    return q
}

func (q *Query) Limit(n int) *Query {
    q.limit = n
    return q
}

Теперь вы можете chain эти вызовы fluently:

query := &Query{}
query.Select("name", "email").From("users").Where("active = true").Limit(10)

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

Помни, что each метод должен использовать получатель-указатель и возвращать *StructType, чтобы chain работала правильно.

challenge icon

Задание

Легко

Давайте создадим fluent builder HTML-элементов, использующий цепочку методов для конструирования HTML-тегов с атрибутами и содержимым! Это практическое применение цепочки методов: вы создадите API, который при создании HTML-элементов читается почти как естественный язык.

Вы организуете код в двух файлах:

  • element.go: Define builder HTML-элементов с методами, поддерживающими chaining.

    Create структуру Element, которая хранит имя тега, map атрибутов (string в string) и inner content. Build следующие методы, поддерживающие chaining, каждый из которых возвращает *Element:

    • NewElement(tag string) — конструктор, который creates новый Element с заданным именем тега и initialized (empty) map атрибутов
    • Attr(key, value string) — adds атрибут к элементу
    • ID(id string) — convenience метод, который устанавливает атрибут "id"
    • Class(class string) — convenience метод, который устанавливает атрибут "class"
    • Content(text string) — устанавливает inner content элемента

    Добавьте метод Render(), который возвращает строку HTML. Атрибуты должны appear в alphabetical порядке по key. Формат:

    <tag attr1="value1" attr2="value2">content</tag>

    Если атрибутов нет, просто выведите <tag>content</tag>. Если content отсутствует, выведите <tag attr="value"></tag>.

  • main.go: Build HTML-элементы с помощью chaining методов.

    Прочитайте имя тега, затем прочитайте количество операций, которые нужно выполнить. Каждая операция представляет собой один из вариантов:

    • id, за которым следует значение ID
    • class, за которым следует значение class
    • attr, за которым следуют имя и значение атрибута (две строки)
    • content, за которым следует текст content

    Соедините все операции в цепочку fluently, затем выведите HTML после render.

Будут предоставлены следующие входные данные:

  • Строка 1: имя тега
  • Строка 2: количество операций
  • Следующие строки: тип операции и значение(я)

Например, для входных данных:

div
3
id
container
class
main-content
content
Hello World

Ваш вывод должен быть таким:

<div class="main-content" id="container">Hello World</div>

А для входных данных:

a
3
attr
href
https://example.com
attr
target
_blank
content
Click here

Ваш вывод должен быть таким:

<a href="https://example.com" target="_blank">Click here</a>

А для входных данных:

input
2
attr
type
text
attr
placeholder
Enter name

Ваш вывод должен быть таким:

<input placeholder="Enter name" type="text"></input>

А для входных данных:

p
1
content
Simple paragraph

Ваш вывод должен быть таким:

<p>Simple paragraph</p>

Обратите внимание, как chaining методов позволяет пошагово создавать элементы в удобном для чтения виде. Каждый метод изменяет элемент и возвращает его, позволяя напрямую присоединить к цепочке следующий вызов метода.

Попробуйте сами

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)

	// Прочитать имя тега
	scanner.Scan()
	tagName := scanner.Text()

	// Прочитать количество операций
	scanner.Scan()
	numOps, _ := strconv.Atoi(scanner.Text())

	// Создать элемент
	element := NewElement(tagName)

	// Обработать каждую операцию
	for i := 0; i < numOps; i++ {
		scanner.Scan()
		operation := scanner.Text()

		// TODO: В зависимости от типа операции вызвать соответствующий метод в цепочке
		// Операции могут быть: "id", "class", "attr" или "content"
		// - Для "id": прочитать следующую строку как значение ID
		// - Для "class": прочитать следующую строку как значение class
		// - Для "attr": прочитать следующие ДВЕ строки (имя атрибута, затем значение)
		// - Для "content": прочитать следующую строку как текст содержимого
		// Использовать цепочку методов для плавного построения элемента

		_ = operation // Удалить эту строку при реализации
	}

	// Вывести отрендеренный HTML
	fmt.Println(element.Render())
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Go