Education 1.1 Help

Принцип единственной ответственности

Принцип единой ответственности гласит, что у каждого класса должна быть только одна «ответственность» и он не должен брать на себя другие обязанности. Роберт К. Мартин объяснял его так: «У класса должна быть лишь одна причина для изменения». Давайте в качестве примера возьмем приложение телефонного справочника. Мы будем делать телефонный справочник, в котором будет класс TelephoneDirectory. Он будет «нести ответственность» за ведение записей справочника, то есть телефонных номеров и названий организаций, которым принадлежат номера. Ожидается, что класс будет выполнять следующие операции:

  • добавлять новую запись (Name и Telephone Number)

  • удалять существующую запись

  • изменять номер телефона, присвоенный сущности Name

  • предоставлять поиск, который будет возвращать номер, присвоенный сущности Name.

Класс TelephoneDirectory может выглядеть следующим образом:

class TelephoneDirectory: def __init__(self): self.telephone_directory = dict() def add_entry(self, name, number): self.telephone_directory[name] = number def delete_entry(self, name): del self.telephone_directory[name] def update_entry(self, name, number): self.telephone_directory[name] = number def lookup_number(self, name): return self.telephone_directory.get(name) def __str__(self): ret_dct = '' for key, value in self.telephone_directory.items(): ret_dct += f'{key} : {value}\n' return ret_dct phone_book = TelephoneDirectory() phone_book.add_entry('Ravi', 123456) phone_book.add_entry('Vikas', 67890) print(phone_book) phone_book.delete_entry('Ravi') phone_book.add_entry('Ravi', 123456) phone_book.update_entry('Vikas', 776589) print(phone_book.lookup_number('Vikas')) print(phone_book)
class TelephoneDirectory { private array $telephone_directory = []; public function add_entry(string $name, string $number) { $this->telephone_directory[$name] = $number; } public function delete_entry(string $name) { if (array_key_exists($name, $this->$telephone_directory)) { unset($this->telephone_directory[$name]); } } public function update_entry(string $name, string $number) { $this->telephone_directory[$name] = $number; } public function lookup_number(string $name) { if (array_key_exists($name, $this->$telephone_directory)) { return $this->telephone_directory[$name]; } return null; } public function __toString() { $data = []; foreach ($this->$telephone_directory as $name => $phone) { $data[] = $name . ' : ' . $phone; } return implode(PHP_EOL, $data); } } $phone_book = new TelephoneDirectory() $phone_book->add_entry('Ravi', 123456) $phone_book->add_entry('Vikas', 67890) echo $phone_book; echo PHP_EOL; $phone_book->delete_entry('Ravi') $phone_book->add_entry('Ravi', 123456) $phone_book->update_entry('Vikas', 776589) echo $phone_book->lookup_number('Vikas'); echo PHP_EOL; echo $phone_book;
Ravi : 123456 Vikas : 67890 776589 Vikas : 776589 Ravi : 123456

Сейчас наш класс TelephoneDirectory выглядит хорошо, в нем точно реализованы ожидаемые функции: А теперь скажем, что в проекте есть еще два требования – Сохранить содержимое справочника в базе данных и перенести содержимое справочника в файл. Теперь добавим еще два метода в класс TelephoneDirectory, как показано ниже:

class TelephoneDirectory: def __init__(self): self.telephone_directory = dict() def add_entry(self, name, number): self.telephone_directory[name] = number def delete_entry(self, name): del self.telephone_directory[name] def update_entry(self, name, number): self.telephone_directory[name] = number def lookup_number(self, name): return self.telephone_directory.get(name) def save_to_file(self, file_name, location): #код для сохранения телефонного справочника в файл pass def persist_to_database(self, database_details): #код для сохранения телефонного справочника в базу данных pass def __str__(self): ret_dct = '' for key, value in self.telephone_directory.items(): ret_dct += f'{key} : {value}\n' return ret_dct
class TelephoneDirectory { private array $telephone_directory = []; public function add_entry(string $name, string $number) { $this->telephone_directory[$name] = $number; } public function delete_entry(string $name) { if (array_key_exists($name, $this->$telephone_directory)) { unset($this->telephone_directory[$name]); } } public function update_entry(string $name, string $number) { $this->telephone_directory[$name] = $number; } public function lookup_number(string $name) { if (array_key_exists($name, $this->$telephone_directory)) { return $this->telephone_directory[$name]; } return null; } public function __toString() { $data = []; foreach ($this->$telephone_directory as $name => $phone) { $data[] = $name . ' : ' . $phone; } return implode(PHP_EOL, $data); } public function save_to_file(string $file_name, string $location) { // код для сохранения телефонного справочника в файл } public function persist_to_database(string $database_details) { // код для сохранения телефонного справочника в базу данных } }

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

class PersistToDatabase: def __init__(self, object_to_persist): pass class SaveToFile: def __init__(self, object_to_save): pass
class PersistToDatabase { public function __construct (TelephoneDirectory $object_to_persist) { // сохранение в базу данных } } class SaveToFile { public function __construct (TelephoneDirectory $object_to_save) { // сохранение в файл } }
Last modified: 12 June 2024