Что такое сеттер в программировании
Перейти к содержимому

Что такое сеттер в программировании

  • автор:

Сеттер или геттер-ссылка — как сделать правильный выбор?

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

Сделать это можно двумя способами:

  • С помощью сеттера, метода, который принимает новое значение атрибута в качестве аргумента.
  • С помощью геттера-ссылки (reference-getter), метода, который возвращает ссылку на сам атрибут.

Вот небольшой пример, показывающий, как с помощью двух этих методов получить доступ к полю bar .

class Foo < int m_bar; public: //Сеттер void set_bar(int bar) < m_bar = bar; >//Геттер-ссылка int & get_bar() < return m_bar; >>; int main() < Foo foo; //Редактирование через сеттер foo.set_bar(42); //Редактирование с помощью геттер-ссылки foo.get_bar() = 84; return 0; >

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

Сеттер

Сеттер по отношению к классу является интерфейсом только для записи (write-only). Вы указываете значение, и соответственно обновляете класс.

Зачастую он более или менее напрямую обновляет атрибут, копируя/перемещая(move) предоставленные вами данные.

// Самый примитивный сеттер void set_foo(int foo)
// Сеттер, который делает проверку перед присваиванием void set_foo(Foo foo)
// move-сеттер void set_big_foo(BigFoo && big_foo) < m_big_foo = std::forward(big_foo); >
Геттер-ссылка

Геттер-ссылка (reference-getter) представляет собой метод, который возвращает ссылку на атрибут, что дает непосредственный доступ к нему, в том числе предоставляя возможность его редактирования.

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

// Here is the implementation of the reference-getter Foo & MyClass::get_foo() < return m_foo; >// . // Used to edit an attribute myClass.getFoo().bar = 42; // Used to call a non-const method myClass.getFoo().udpate();
Какой метод выбрать?

Сделать выбор станет довольно просто, как только вы поймете разницу между ними.

Когда вам нужно пересоздать данные и поместить их на место уже существующих, вам пригодится сеттер. Он также подходит для редактирования простых данных (целые числа, значения чисел с плавающей запятой, указатели и т. д.) или если вам нужно подставить полностью новое значение. Еще один вариант использования сеттеров: когда вы намеренно хотите дать пользователю возможность только редактировать данные, но не читать.

Геттер-ссылка вам пригодится для редактирования данных атрибута (а не атрибута целиком). Часто нам необходимо отредактировать только часть атрибута или вызвать для них неконстантный метод.

Другими словами, сеттер заменяет атрибут, а геттер-ссылка редактирует атрибут.

Пример

Рассмотрим следующий код:

#include using namespace std; struct Item < bool validity; int value; >; class Foo < public: Foo(size_t size) : m_max_size(size), m_data(size, ) <> void set_max_size(size_t max_size) < m_max_size = max_size; >Item & get_item(size_t index) < return m_data.at(index); >size_t get_data_size() const < return m_data.size(); >private: bool m_max_size; std::vector m_data; >; static void set_foo_size(Foo & foo, size_t new_size)

В коде представлен простой класс, который содержит набор данных (Item’ы). Эти данные могут быть валидными или невалидными ( true — валидные, false — невалидные).

Затем мы реализуем небольшую функцию, которая изменяет размер коллекции, не удаляя никаких элементов. Элементы, выходящие за заданный размер, становятся невалидными.

Мы задаем значение m_max_size с помощью сеттера, так как это обычное целое число, значение которого меняется при изменении размера коллекции.

С помощью геттер-ссылки мы можем получить доступ к каждому Item ‘у из m_data , так как нам не всегда требуется полностью удалять item , иногда нам необходимо просто отредактировать его часть.

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

class Foo < // . void set_item_validity(size_t index, bool validity) < m_data.at(index).validity = validity; >// . >;

Сделав так, мы бы потеряли возможность редактировать value Item ,поэтому это решение полностью зависит от деталей вашей реализации.

Однако, пожалуйста, помните, что писать сеттеры и для value и для validity является плохой практикой. Делать это в корзине данных с двумя атрибутами вряд ли будет правильным решением, потому что как только ваша реализация начнет расти, ваша кодовая база будет переполнена бесполезными аксессорами. Вам нужен полный доступ? Так и реализуйте полный доступ.

Заключение

Многие из вас посчитают эту тему тривиальной, но многие разработчики все еще путаются, когда следует использовать сеттер, а когда геттер-ссылку. Будьте внимательны.

Материал подготовлен в рамках специализации «C++ Developer».

Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем специализации — приглашаем на день открытых дверей онлайн. Регистрация здесь.

  • Блог компании OTUS
  • Программирование
  • C++

Сеттер программирование У этого термина существуют и другие значения см Сеттер значения Сеттер англ setter также устанав

Сеттер (англ. setter , также устанавливающий метод, модифицирующий метод, мутатор) — метод, используемый в объектно-ориентированном программировании для присвоения какого-либо значения инкапсулированному полю, например, обработав при этом недопустимые присваивания. Часто реализуется в паре с методом-геттером, позволяющим получать значение поля класса.

Примеры Править

public class ScheduleTask  private int hours; public void setHours(int hours)  if ((hours >= 0) && (hours  24)) this.hours = hours; > > 

Здесь для изменения скрытого поля hours нужно использовать сеттер setHours , который будет следить за тем, чтобы оно принимало только допустимые значения.

В C# благодаря синтаксическим возможностям (контекстные ключевые слова set и value — использующееся только в сеттере) чаще применяется другая методика:

public class ScheduleTask  private int hours; public int Hours  set  if ( (value >= 0) && (value  24) )  hours = value; > > > > 

При этом возможно использование и через публичный метод, так как фактически конструкцию set < . >компилятор C# преобразует в метод класса.

Сеттер в VB.NET обязан иметь модификатор WriteOnly, если не будет реализован геттер:

Public Class Foo Private m_Data As Integer 'Закрытое поле с данными Public Property Message As Integer 'Автореализуемое свойство, начиная с VB 10.0 Public WriteOnly Property Data As Integer 'Открытое свойство только для записи Set(Value As Integer) m_Data = Value End Set End Property End Class 

В статье не хватает ссылок на источники (см. рекомендации по поиску).

Информация должна быть проверяема, иначе она может быть удалена. Вы можете отредактировать статью, добавив ссылки на авторитетные источники в виде сносок. ( 28 сентября 2014 )

Википедия, чтение, книга, библиотека, поиск, нажмите, истории, книги, статьи, wikipedia, учить, информация, история, скачать, скачать бесплатно, mp3, видео, mp4, 3gp, jpg, jpeg, gif, png, картинка, музыка, песня, фильм, игра, игры

Дата публикации: Октябрь 05, 2023, 20:28 pm
Самые читаемые

Уиллем I, граф Росс

Тюпиньи

Тэцудзин 28 Го

Трубецкой, Дмитрий Юрьевич

Третье убийство

Трегубов, Симеон Иванович

Троицкое благочиние

Туюксу (перевал)

Турченко, Николай Архипович

Тункинское сельское поселение

© Copyright 2021, Все права защищены.

U etogo termina sushestvuyut i drugie znacheniya sm Setter znacheniya Setter angl setter takzhe ustanavlivayushij metod modificiruyushij metod mutator metod ispolzuemyj v obektno orientirovannom programmirovanii dlya prisvoeniya kakogo libo znacheniya inkapsulirovannomu polyu naprimer obrabotav pri etom nedopustimye prisvaivaniya Chasto realizuetsya v pare s metodom getterom pozvolyayushim poluchat znachenie polya klassa Primery PravitPrimer na Java public class ScheduleTask private int hours public void setHours int hours if hours gt 0 amp amp hours lt 24 this hours hours Zdes dlya izmeneniya skrytogo polya hours nuzhno ispolzovat setter setHours kotoryj budet sledit za tem chtoby ono prinimalo tolko dopustimye znacheniya V C blagodarya sintaksicheskim vozmozhnostyam kontekstnye klyuchevye slova set i value ispolzuyusheesya tolko v settere chashe primenyaetsya drugaya metodika public class ScheduleTask private int hours public int Hours set if value gt 0 amp amp value lt 24 hours value Pri etom vozmozhno ispolzovanie i cherez publichnyj metod tak kak fakticheski konstrukciyu set kompilyator C preobrazuet v metod klassa Setter v VB NET obyazan imet modifikator WriteOnly esli ne budet realizovan getter Public Class Foo Private m Data As Integer Zakrytoe pole s dannymi Public Property Message As Integer Avtorealizuemoe svojstvo nachinaya s VB 10 0 Public WriteOnly Property Data As Integer Otkrytoe svojstvo tolko dlya zapisi Set Value As Integer m Data Value End Set End Property End Class V state ne hvataet ssylok na istochniki sm rekomendacii po poisku Informaciya dolzhna byt proveryaema inache ona mozhet byt udalena Vy mozhete otredaktirovat statyu dobaviv ssylki na avtoritetnye istochniki v vide snosok 28 sentyabrya 2014 Istochnik https ru wikipedia org w index php title Setter programmirovanie amp oldid 114775007

Свойства — геттеры и сеттеры

Первый тип это свойства-данные (data properties). Мы уже знаем, как работать с ними. Все свойства, которые мы использовали до текущего момента, были свойствами-данными.

Второй тип свойств мы ещё не рассматривали. Это свойства-аксессоры (accessor properties). По своей сути это функции, которые используются для присвоения и получения значения, но во внешнем коде они выглядят как обычные свойства объекта.

Геттеры и сеттеры

Свойства-аксессоры представлены методами: «геттер» – для чтения и «сеттер» – для записи. При литеральном объявлении объекта они обозначаются get и set :

let obj = < get propName() < // геттер, срабатывает при чтении obj.propName >, set propName(value) < // сеттер, срабатывает при записи obj.propName = value >>;

Геттер срабатывает, когда obj.propName читается, сеттер – когда значение присваивается.

Например, у нас есть объект user со свойствами name и surname :

let user = < name: "John", surname: "Smith" >;

А теперь добавим свойство объекта fullName для полного имени, которое в нашем случае «John Smith» . Само собой, мы не хотим дублировать уже имеющуюся информацию, так что реализуем его при помощи аксессора:

let user = < name: "John", surname: "Smith", get fullName() < return `$$`; > >; alert(user.fullName); // John Smith

Снаружи свойство-аксессор выглядит как обычное свойство. В этом и заключается смысл свойств-аксессоров. Мы не вызываем user.fullName как функцию, а читаем как обычное свойство: геттер выполнит всю работу за кулисами.

На данный момент у fullName есть только геттер. Если мы попытаемся назначить user.fullName= , произойдёт ошибка:

let user = < get fullName() < return `. `; >>; user.fullName = "Тест"; // Ошибка (у свойства есть только геттер)

Давайте исправим это, добавив сеттер для user.fullName :

let user = < name: "John", surname: "Smith", get fullName() < return `$$`; >, set fullName(value) < [this.name, this.surname] = value.split(" "); >>; // set fullName запустится с данным значением user.fullName = "Alice Cooper"; alert(user.name); // Alice alert(user.surname); // Cooper

В итоге мы получили «виртуальное» свойство fullName . Его можно прочитать и изменить.

Дескрипторы свойств доступа

Дескрипторы свойств-аксессоров отличаются от «обычных» свойств-данных.

Свойства-аксессоры не имеют value и writable , но взамен предлагают функции get и set .

То есть, дескриптор аксессора может иметь:

  • get – функция без аргументов, которая сработает при чтении свойства,
  • set – функция, принимающая один аргумент, вызываемая при присвоении свойства,
  • enumerable – то же самое, что и для свойств-данных,
  • configurable – то же самое, что и для свойств-данных.

Например, для создания аксессора fullName при помощи defineProperty мы можем передать дескриптор с использованием get и set :

let user = < name: "John", surname: "Smith" >; Object.defineProperty(user, 'fullName', < get() < return `$$`; >, set(value) < [this.name, this.surname] = value.split(" "); >>); alert(user.fullName); // John Smith for(let key in user) alert(key); // name, surname

Ещё раз заметим, что свойство объекта может быть либо свойством-аксессором (с методами get/set ), либо свойством-данным (со значением value ).

При попытке указать и get , и value в одном дескрипторе будет ошибка:

// Error: Invalid property descriptor. Object.defineProperty(<>, 'prop', < get() < return 1 >, value: 2 >);

Умные геттеры/сеттеры

Геттеры/сеттеры можно использовать как обёртки над «реальными» значениями свойств, чтобы получить больше контроля над операциями с ними.

Например, если мы хотим запретить устанавливать короткое имя для user , мы можем использовать сеттер name для проверки, а само значение хранить в отдельном свойстве _name :

let user = < get name() < return this._name; >, set name(value) < if (value.length < 4) < alert("Имя слишком короткое, должно быть более 4 символов"); return; >this._name = value; > >; user.name = "Pete"; alert(user.name); // Pete user.name = ""; // Имя слишком короткое. 

Таким образом, само имя хранится в _name , доступ к которому производится через геттер и сеттер.

Технически, внешний код всё ещё может получить доступ к имени напрямую с помощью user._name , но существует широко известное соглашение о том, что свойства, которые начинаются с символа «_» , являются внутренними, и к ним не следует обращаться из-за пределов объекта.

Использование для совместимости

У аксессоров есть интересная область применения – они позволяют в любой момент взять «обычное» свойство и изменить его поведение, поменяв на геттер и сеттер.

Например, представим, что мы начали реализовывать объект user , используя свойства-данные имя name и возраст age :

function User(name, age) < this.name = name; this.age = age; >let john = new User("John", 25); alert( john.age ); // 25

…Но рано или поздно всё может измениться. Взамен возраста age мы можем решить хранить дату рождения birthday , потому что так более точно и удобно:

function User(name, birthday) < this.name = name; this.birthday = birthday; >let john = new User("John", new Date(1992, 6, 1));

Что нам делать со старым кодом, который использует свойство age ?

Мы можем попытаться найти все такие места и изменить их, но это отнимает время и может быть невыполнимо, если код используется другими людьми. И кроме того, age – это отличное свойство для user , верно?

Давайте его сохраним.

Добавление геттера для age решит проблему:

function User(name, birthday) < this.name = name; this.birthday = birthday; // возраст рассчитывается из текущей даты и дня рождения Object.defineProperty(this, "age", < get() < let todayYear = new Date().getFullYear(); return todayYear - this.birthday.getFullYear(); >>); > let john = new User("John", new Date(1992, 6, 1)); alert( john.birthday ); // доступен как день рождения alert( john.age ); // . так и возраст

Теперь старый код тоже работает, и у нас есть отличное дополнительное свойство!

Геттеры и сеттеры

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

Для управляемого доступа к состоянию объекта используют специальные функции, так называемые «геттеры» и «сеттеры».

Геттер и сеттер для воды

На текущий момент количество воды в кофеварке является публичным свойством waterAmount :

function CoffeeMachine(power) < // количество воды в кофеварке this.waterAmount = 0; . >

Это немного опасно. Ведь в это свойство можно записать произвольное количество воды, хоть весь мировой океан.

// не помещается в кофеварку! coffeeMachine.waterAmount = 1000000;

Это ещё ничего, гораздо хуже, что можно наоборот – вылить больше, чем есть:

// и не волнует, было ли там столько воды вообще! coffeeMachine.waterAmount -= 1000000;

Так происходит потому, что свойство полностью доступно снаружи.

Чтобы не было таких казусов, нам нужно ограничить контроль над свойством со стороны внешнего кода.

Для лучшего контроля над свойством его делают приватным, а запись значения осуществляется через специальный метод, который называют «сеттер» (setter method).

Типичное название для сеттера – setСвойство , например, в случае с кофеваркой таким сеттером будет метод setWaterAmount :

function CoffeeMachine(power, capacity) < // capacity - ёмкость кофеварки var waterAmount = 0; var WATER_HEAT_CAPACITY = 4200; function getTimeToBoil() < return waterAmount * WATER_HEAT_CAPACITY * 80 / power; >// "умная" установка свойства this.setWaterAmount = function(amount) < if (amount < 0) < throw new Error("Значение должно быть положительным"); >if (amount > capacity) < throw new Error("Нельзя залить воды больше, чем " + capacity); >waterAmount = amount; >; function onReady() < alert( 'Кофе готов!' ); >this.run = function() < setTimeout(onReady, getTimeToBoil()); >; > var coffeeMachine = new CoffeeMachine(1000, 500); coffeeMachine.setWaterAmount(600); // упс, ошибка!

Теперь waterAmount – внутреннее свойство, его можно записать (через сеттер), но, увы, нельзя прочитать.

Для того, чтобы дать возможность внешнему коду узнать его значение, создадим специальную функцию – «геттер» (getter method).

Геттеры обычно имеют название вида getСвойство , в данном случае getWaterAmount :

function CoffeeMachine(power, capacity) < //. this.setWaterAmount = function(amount) < if (amount < 0) < throw new Error("Значение должно быть положительным"); >if (amount > capacity) < throw new Error("Нельзя залить воды больше, чем " + capacity); >waterAmount = amount; >; this.getWaterAmount = function() < return waterAmount; >; > var coffeeMachine = new CoffeeMachine(1000, 500); coffeeMachine.setWaterAmount(450); alert( coffeeMachine.getWaterAmount() ); // 450

Единый геттер-сеттер

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

При вызове без параметров такой метод возвращает свойство, а при передаче параметра – назначает его.

Выглядит это так:

function CoffeeMachine(power, capacity) < var waterAmount = 0; this.waterAmount = function(amount) < // вызов без параметра, значит режим геттера, возвращаем свойство if (!arguments.length) return waterAmount; // иначе режим сеттера if (amount < 0) < throw new Error("Значение должно быть положительным"); >if (amount > capacity) < throw new Error("Нельзя залить воды больше, чем " + capacity); >waterAmount = amount; >; > var coffeeMachine = new CoffeeMachine(1000, 500); // пример использования coffeeMachine.waterAmount(450); alert( coffeeMachine.waterAmount() ); // 450

Единый геттер-сеттер используется реже, чем две отдельные функции, но в некоторых JavaScript-библиотеках, например jQuery и D3, подобный подход принят на уровне концепта.

Итого

  • Для большего контроля над присвоением и чтением значения вместо свойства делают «функцию-геттер» и «функцию-сеттер», геттер возвращает значение, сеттер – устанавливает.
  • Если свойство предназначено только для чтения, то может быть только геттер, только для записи – только сеттер.
  • В качестве альтернативы к паре геттер/сеттер применяют единую функцию, которая без аргументов ведёт себя как геттер, а с аргументом – как сеттер.

Также можно организовать геттеры/сеттеры для свойства, не меняя структуры кода, через дескрипторы свойств.

Задачи

Написать объект с геттерами и сеттерами

важность: 4

Напишите конструктор User для создания объектов:

  • С приватными свойствами имя firstName и фамилия surname .
  • С сеттерами для этих свойств.
  • С геттером getFullName() , который возвращает полное имя.

Должен работать так:

function User() < /* ваш код */ >var user = new User(); user.setFirstName("Петя"); user.setSurname("Иванов"); alert( user.getFullName() ); // Петя Иванов
function User() < var firstName, surname; this.setFirstName = function(newFirstName) < firstName = newFirstName; >; this.setSurname = function(newSurname) < surname = newSurname; >; this.getFullName = function() < return firstName + ' ' + surname; >> var user = new User(); user.setFirstName("Петя"); user.setSurname("Иванов"); alert( user.getFullName() ); // Петя Иванов

Обратим внимание, что для «геттера» getFullName нет соответствующего свойства объекта, он конструирует ответ «на лету». Это нормально. Одна из целей существования геттеров/сеттеров – как раз и есть изоляция внутренних свойств объекта, чтобы можно было их как угодно менять, генерировать «на лету», а внешний интерфейс оставался тем же.

Добавить геттер для power

важность: 5

Добавьте кофеварке геттер для приватного свойства power , чтобы внешний код мог узнать мощность кофеварки.

function CoffeeMachine(power, capacity) < //. this.setWaterAmount = function(amount) < if (amount < 0) < throw new Error("Значение должно быть положительным"); >if (amount > capacity) < throw new Error("Нельзя залить воды больше, чем " + capacity); >waterAmount = amount; >; this.getWaterAmount = function() < return waterAmount; >; >

Обратим внимание, что ситуация, когда у свойства power есть геттер, но нет сеттера – вполне обычна.

Здесь это означает, что мощность power можно указать лишь при создании кофеварки и в дальнейшем её можно прочитать, но нельзя изменить.

function CoffeeMachine(power, capacity) < //. this.setWaterAmount = function(amount) < if (amount < 0) < throw new Error("Значение должно быть положительным"); >if (amount > capacity) < throw new Error("Нельзя залить воды больше, чем " + capacity); >waterAmount = amount; >; this.getWaterAmount = function() < return waterAmount; >; this.getPower = function() < return power; >; >

Добавить публичный метод кофеварке

важность: 5

Добавьте кофеварке публичный метод addWater(amount) , который будет добавлять воду.

При этом, конечно же, должны происходить все необходимые проверки – на положительность и превышение ёмкости.

function CoffeeMachine(power, capacity) < var waterAmount = 0; var WATER_HEAT_CAPACITY = 4200; function getTimeToBoil() < return waterAmount * WATER_HEAT_CAPACITY * 80 / power; >this.setWaterAmount = function(amount) < if (amount < 0) < throw new Error("Значение должно быть положительным"); >if (amount > capacity) < throw new Error("Нельзя залить больше, чем " + capacity); >waterAmount = amount; >; function onReady() < alert( 'Кофе готов!' ); >this.run = function() < setTimeout(onReady, getTimeToBoil()); >; >

Вот такой код должен приводить к ошибке:

var coffeeMachine = new CoffeeMachine(100000, 400); coffeeMachine.addWater(200); coffeeMachine.addWater(100); coffeeMachine.addWater(300); // Нельзя залить больше, чем 400 coffeeMachine.run();

В решении ниже addWater будет просто вызывать setWaterAmount .

function CoffeeMachine(power, capacity) < var waterAmount = 0; var WATER_HEAT_CAPACITY = 4200; function getTimeToBoil() < return waterAmount * WATER_HEAT_CAPACITY * 80 / power; >this.setWaterAmount = function(amount) < if (amount < 0) < throw new Error("Значение должно быть положительным"); >if (amount > capacity) < throw new Error("Нельзя залить больше, чем " + capacity); >waterAmount = amount; >; this.addWater = function(amount) < this.setWaterAmount(waterAmount + amount); >; function onReady() < alert( 'Кофе готов!' ); >this.run = function() < setTimeout(onReady, getTimeToBoil()); >; > var coffeeMachine = new CoffeeMachine(100000, 400); coffeeMachine.addWater(200); coffeeMachine.addWater(100); coffeeMachine.addWater(300); // Нельзя залить больше.. coffeeMachine.run();

Создать сеттер для onReady

важность: 5

Обычно когда кофе готов, мы хотим что-то сделать, например выпить его.

Сейчас при готовности срабатывает функция onReady , но она жёстко задана в коде:

function CoffeeMachine(power, capacity) < var waterAmount = 0; var WATER_HEAT_CAPACITY = 4200; function getTimeToBoil() < return waterAmount * WATER_HEAT_CAPACITY * 80 / power; >this.setWaterAmount = function(amount) < // . проверки пропущены для краткости waterAmount = amount; >; this.getWaterAmount = function(amount) < return waterAmount; >; function onReady() < alert( 'Кофе готов!' ); >this.run = function() < setTimeout(onReady, getTimeToBoil()); >; >

Создайте сеттер setOnReady , чтобы код снаружи мог назначить свой onReady , вот так:

var coffeeMachine = new CoffeeMachine(20000, 500); coffeeMachine.setWaterAmount(150); coffeeMachine.setOnReady(function() < var amount = coffeeMachine.getWaterAmount(); alert( 'Готов кофе: ' + amount + 'мл' ); // Кофе готов: 150 мл >); coffeeMachine.run();

P.S. Значение onReady по умолчанию должно быть таким же, как и раньше.

P.P.S. Постарайтесь сделать так, чтобы setOnReady можно было вызвать не только до, но и после запуска кофеварки, то есть чтобы функцию onReady можно было изменить в любой момент до её срабатывания.

function CoffeeMachine(power, capacity) < var waterAmount = 0; var WATER_HEAT_CAPACITY = 4200; function getTimeToBoil() < return waterAmount * WATER_HEAT_CAPACITY * 80 / power; >this.setWaterAmount = function(amount) < // . проверки пропущены для краткости waterAmount = amount; >; this.getWaterAmount = function(amount) < return waterAmount; >; function onReady() < alert( 'Кофе готов!' ); >this.setOnReady = function(newOnReady) < onReady = newOnReady; >; this.run = function() < setTimeout(function() < onReady(); >, getTimeToBoil()); >; > var coffeeMachine = new CoffeeMachine(20000, 500); coffeeMachine.setWaterAmount(150); coffeeMachine.run(); coffeeMachine.setOnReady(function() < var amount = coffeeMachine.getWaterAmount(); alert( 'Готов кофе: ' + amount + 'мл' ); // Готов кофе: 150 мл >);

Обратите внимание на два момента в решении:

    В сеттере setOnReady параметр называется newOnReady . Мы не можем назвать его onReady , так как тогда изнутри сеттера мы никак не доберёмся до внешнего (старого значения):

// нерабочий вариант this.setOnReady = function(onReady) < onReady = onReady; // . внешняя переменная onReady недоступна >;

Добавить метод isRunning

важность: 5

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

Для этого добавьте кофеварке публичный метод isRunning() , который будет возвращать true , если она запущена и false , если нет.

Нужно, чтобы такой код работал:

var coffeeMachine = new CoffeeMachine(20000, 500); coffeeMachine.setWaterAmount(100); alert( 'До: ' + coffeeMachine.isRunning() ); // До: false coffeeMachine.run(); alert( 'В процессе: ' + coffeeMachine.isRunning() ); // В процессе: true coffeeMachine.setOnReady(function() < alert( "После: " + coffeeMachine.isRunning() ); // После: false >);

Исходный код возьмите из решения предыдущей задачи.

Код решения модифицирует функцию run и добавляет приватный идентификатор таймера timerId , по наличию которого мы судим о состоянии кофеварки:

function CoffeeMachine(power, capacity) < var waterAmount = 0; var timerId; this.isRunning = function() < return !!timerId; >; var WATER_HEAT_CAPACITY = 4200; function getTimeToBoil() < return waterAmount * WATER_HEAT_CAPACITY * 80 / power; >this.setWaterAmount = function(amount) < // . проверки пропущены для краткости waterAmount = amount; >; this.getWaterAmount = function(amount) < return waterAmount; >; function onReady() < alert( 'Кофе готов!' ); >this.setOnReady = function(newOnReady) < onReady = newOnReady; >; this.run = function() < timerId = setTimeout(function() < timerId = null; onReady(); >, getTimeToBoil()); >; > var coffeeMachine = new CoffeeMachine(20000, 500); coffeeMachine.setWaterAmount(100); alert( 'До: ' + coffeeMachine.isRunning() ); // До: false coffeeMachine.run(); alert( 'В процессе: ' + coffeeMachine.isRunning() ); // В процессе: true coffeeMachine.setOnReady(function() < alert( "После: " + coffeeMachine.isRunning() ); // После: false >);

Поделиться

Комментарии

перед тем как писать…

  • Если вам кажется, что в статье что-то не так — вместо комментария напишите на GitHub.
  • Для одной строки кода используйте тег , для нескольких строк кода — тег , если больше 10 строк — ссылку на песочницу (plnkr, JSBin, codepen…)
  • Если что-то непонятно в статье — пишите, что именно и с какого места.
  • © 2007—2024 Илья Кантор
  • о проекте
  • связаться с нами
  • пользовательское соглашение
  • политика конфиденциальности

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *