Skip to content

Latest commit

 

History

History
83 lines (59 loc) · 4.5 KB

Single Responsibility Principle.md

File metadata and controls

83 lines (59 loc) · 4.5 KB

Single Responsibility Principle (принцип единственности ответственности)

«Одно поручение. Всего одно.» — Локи говорит Скурджу в фильме «Тор: Рагнарёк».

На самом верхнем уровне мы декомпозируем систему на пакаджи. В соответствии с этим принципом каждый пакадж должен заниматься какой-то отдельной вещью.

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

Каждый метод структуры выполняет какую-то одну единственную задачу.

Представим, что у нас есть стукртура реализующая интерфейс IAnimal

type IAnimal interface {
	GetAnimal() string
	SaveAnimal()
}
type Animal struct {
	name string
}

func (animal *Animal) GetAnimal() string {
	return animal.name
}

func (animal *Animal) SaveAnimal() {
	// impl
}

Стуктура Animal, представленная здесь, описывает какое-то животное. Эта стуктура нарушает принцип единственной ответственности. Как именно нарушается этот принцип?

В соответствии с принципом единственной ответственности структура должена решать лишь какую-то одну задачу. Она же решает две, занимаясь работой с хранилищем данных в методе SaveAnimal и манипулируя свойствами объекта в методе GetAnimal.

Как такая структура класса может привести к проблемам?

Если изменится порядок работы с хранилищем данных, используемым приложением, то придётся вносить изменения во все структуры, работающие с хранилищем. Такая архитектура не отличается гибкостью, изменения одних подсистем затрагивают другие, что напоминает эффект домино.

Для того чтобы привести вышеприведённый код в соответствие с принципом единственной ответственности, создадим ещё одну стуктуру, единственной задачей которой является работа с хранилищем, в частности — сохранение в нём объектов структуры.

type IAnimal interface {
	GetAnimal() string
}

type IAnimalStorage interface {
	Save(animal Animal)
	Get(animal Animal)
}

type AnimalStorage struct {}
func (storage *AnimalStorage) Save(animal Animal) {
	// impl
}

func (storage *AnimalStorage) Get(animal Animal) {
	// impl
}

type Animal struct {
	name string
}

func (animal *Animal) GetName() string {
	return animal.name
}

Вот что по этому поводу говорит Стив Фентон:

Проектируя классы, мы должны стремиться к тому, чтобы объединять родственные компоненты, то есть такие, изменения в которых происходят по одним и тем же причинам. Нам следует стараться разделять компоненты, изменения в которых вызывают различные причины.

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

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