├── .gitignore ├── README.md ├── abstractClass ├── example1 │ └── program1.go ├── example2 │ └── program2.go └── example3 │ └── program3.go ├── docs ├── abstract_class.md ├── compile-time_polymorphism.md ├── encapsulation.md ├── inheritance.md ├── polymorphism.md └── run-time_polymorphism.md ├── encapsulation ├── main.go ├── model │ └── data.go └── view │ └── test.go ├── go.mod ├── inheritance ├── example1 │ └── program1.go ├── example2 │ └── program2.go ├── example3 │ └── program3.go ├── example4 │ └── program4.go ├── example5 │ └── program5.go └── example6 │ └── program6.go └── polymorphism ├── example1 └── program1.go ├── example2 └── program2.go └── example3 └── program3.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Object-Oriented Programming in Go 2 | 3 | * [Inheritance](https://golangbyexample.com/oop-inheritance-golang-complete/) 4 | * [Polymorphism](https://golangbyexample.com/oop-polymorphism-in-go-complete-guide/) 5 | * [Abstract Classes](https://golangbyexample.com/go-abstract-class/) 6 | * [Encapsulation](https://golangbyexample.com/encapsulation-in-go/) 7 | 8 | # Объектно-ориентированное программирование в Go 9 | 10 | Оригиналы доступны выше по ссылкам. 11 | Переводы доступы в репозитории. 12 | 13 | * [Наследование](docs/inheritance.md) 14 | * [Полиморфизм](docs/polymorphism.md) 15 | * [Абстрактные классы](docs/abstract_class.md) 16 | * [Инкапсуляция](docs/encapsulation.md) -------------------------------------------------------------------------------- /abstractClass/example1/program1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Абстрактный интерфейс 6 | type iAlpha interface { 7 | work() 8 | common() 9 | } 10 | 11 | // Абстрактный конкретный тип 12 | type alpha struct { 13 | name string 14 | } 15 | 16 | func (a *alpha) common() { 17 | fmt.Println("common called") 18 | } 19 | 20 | // Реализуем тип 21 | type beta struct { 22 | alpha 23 | } 24 | 25 | func (b *beta) work() { 26 | fmt.Println("work called") 27 | fmt.Printf("name is %s\n", b.name) 28 | b.common() 29 | } 30 | 31 | func main() { 32 | a := alpha{ 33 | name: "test", 34 | } 35 | b := &beta{ 36 | alpha: a, 37 | } 38 | b.work() 39 | } 40 | -------------------------------------------------------------------------------- /abstractClass/example2/program2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Абстрактный интерфейс 6 | type iAlpha interface { 7 | work() 8 | common() 9 | } 10 | 11 | // Абстрактный конкретный тип 12 | type alpha struct { 13 | name string 14 | work func() 15 | } 16 | 17 | func (a *alpha) common() { 18 | fmt.Println("common called") 19 | a.work() 20 | } 21 | 22 | // Реализуем тип 23 | type beta struct { 24 | alpha 25 | } 26 | 27 | func (b *beta) work() { 28 | fmt.Println("work called") 29 | fmt.Printf("name is %s\n", b.name) 30 | } 31 | 32 | func main() { 33 | a := alpha{ 34 | name: "test", 35 | } 36 | b := &beta{ 37 | alpha: a, 38 | } 39 | b.alpha.work = b.work 40 | b.common() 41 | } 42 | -------------------------------------------------------------------------------- /abstractClass/example3/program3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Абстрактный интерфейс 6 | type iAlpha interface { 7 | work() 8 | common(iAlpha) 9 | } 10 | 11 | // Абстрактный конкретный тип 12 | type alpha struct { 13 | name string 14 | } 15 | 16 | func (a *alpha) common(i iAlpha) { 17 | fmt.Println("common called") 18 | i.work() 19 | } 20 | 21 | // Реализуем тип 22 | type beta struct { 23 | alpha 24 | } 25 | 26 | func (b *beta) work() { 27 | fmt.Println("work called") 28 | fmt.Printf("Name is %s\n", b.name) 29 | } 30 | 31 | func main() { 32 | a := alpha{ 33 | name: "test", 34 | } 35 | b := &beta{ 36 | alpha: a, 37 | } 38 | b.common(b) 39 | } 40 | -------------------------------------------------------------------------------- /docs/abstract_class.md: -------------------------------------------------------------------------------- 1 | # Абстрактные классы в Go 2 | 3 | [Оригинал](https://golangbyexample.com/go-abstract-class/) 4 | 5 | Интерфейс в Go не содержит полей, а также не позволяет определять методы внутри 6 | него. Любой тип должен реализовывать все методы интерфейса, чтобы иметь тип 7 | этого интерфейса. Существуют ситуации, когда полезно иметь реализацию метода по 8 | умолчанию, а также поля по умолчанию в Go. Прежде чем понять как это можно 9 | сделать давайте сначала разберёмся с требованиями для абстрактного класса: 10 | 11 | 1. Абстрактный класс должен иметь поля по умолчанию 12 | 2. Абстрактный класс должен иметь метод по умолчанию 13 | 3. Не должно быть возможности непосредственно создать экземпляр абстрактного 14 | класса 15 | 16 | Мы будем использовать комбинацию интерфейса (абстрактный интерфейс) и структуры 17 | (абстрактный конкретный тип). С их помощью можно будет реализовать функционал 18 | абстрактного класса. Смотри программу ниже: 19 | 20 | ```go 21 | package main 22 | 23 | import "fmt" 24 | 25 | // Абстрактный интерфейс 26 | type iAlpha interface { 27 | work() 28 | common() 29 | } 30 | 31 | // Абстрактный конкретный тип 32 | type alpha struct { 33 | name string 34 | } 35 | 36 | func (a *alpha) common() { 37 | fmt.Println("common called") 38 | } 39 | 40 | // Реализуем тип 41 | type beta struct { 42 | alpha 43 | } 44 | 45 | func (b *beta) work() { 46 | fmt.Println("work called") 47 | fmt.Printf("name is %s\n", b.name) 48 | b.common() 49 | } 50 | 51 | func main() { 52 | a := alpha{ 53 | name: "test", 54 | } 55 | b := &beta{ 56 | alpha: a, 57 | } 58 | b.work() 59 | } 60 | ``` 61 | 62 | Результат в терминале: 63 | 64 | ```shell 65 | go run abstractClass/example1/program1.go 66 | work called 67 | name is test 68 | common called 69 | ``` 70 | 71 | В вышеприведенной программе: 72 | 73 | * мы создали абстрактный интерфейс `iAlpha`, абстрактную конкретную структуру 74 | `alpha` и структуру, в которой они реализованы, `beta`. 75 | * Структура `alpha` встроена в `beta` 76 | * Структура `beta` имеет доступ к полю по умолчанию `name` 77 | * Структура `beta` имеет доступ к методу по умолчанию `common` 78 | * Невозможно использовать непосредственно структуру `alpha` не получится, поскольку 79 | она поддерживает только один из методов интерфейса `iAlpha`. 80 | 81 | Таким образом, все требования удовлетворены, но существует одно ограничение 82 | вышеупомянутого способа. Невозможно вызвать метод `work` из `common` в `alpha`. 83 | По сути нет способа вызвать неопределенный метод абстрактного интерфейса из 84 | методов по умолчанию абстрактного конкретного типа. Однако это можно обойти 85 | следующим образом: 86 | 87 | ```go 88 | package main 89 | 90 | import "fmt" 91 | 92 | // Абстрактный интерфейс 93 | type iAlpha interface { 94 | work() 95 | common() 96 | } 97 | 98 | // Абстрактный конкретный тип 99 | type alpha struct { 100 | name string 101 | work func() 102 | } 103 | 104 | func (a *alpha) common() { 105 | fmt.Println("common called") 106 | a.work() 107 | } 108 | 109 | // Реализуем тип 110 | type beta struct { 111 | alpha 112 | } 113 | 114 | func (b *beta) work() { 115 | fmt.Println("work called") 116 | fmt.Printf("name is %s\n", b.name) 117 | } 118 | 119 | func main() { 120 | a := alpha{ 121 | name: "test", 122 | } 123 | b := &beta{ 124 | alpha: a, 125 | } 126 | b.alpha.work = b.work 127 | b.common() 128 | } 129 | ``` 130 | 131 | Результат в терминале: 132 | 133 | ```shell 134 | go run abstractClass/example2/program2.go 135 | common called 136 | work called 137 | name is test 138 | ``` 139 | 140 | В вышеприведенной программе: 141 | * Мы создали новое поле `work` типа `func` в `alpha` 142 | * Мы присвоили методу `work` из `alpha` метод `work` из `beta` 143 | 144 | Единственная проблема в приведенной выше программе заключается в том, что можно 145 | непосредственно создать экземпляр структуры `alpha` и задав определение для 146 | метода `work` она будет удовлетворять типу `iAlpha`. Это нарушает пункт 3 требований 147 | к абстрактному классу. Попробуем исправить эту проблему. Приведенная ниже программа 148 | решает обе проблемы: 149 | 150 | ```go 151 | package main 152 | 153 | import "fmt" 154 | 155 | // Абстрактный интерфейс 156 | type iAlpha interface { 157 | work() 158 | common(iAlpha) 159 | } 160 | 161 | // Абстрактный конкретный тип 162 | type alpha struct { 163 | name string 164 | } 165 | 166 | func (a *alpha) common(i iAlpha) { 167 | fmt.Println("common called") 168 | i.work() 169 | } 170 | 171 | // Реализуем тип 172 | type beta struct { 173 | alpha 174 | } 175 | 176 | func (b *beta) work() { 177 | fmt.Println("work called") 178 | fmt.Printf("name is %s\n", b.name) 179 | } 180 | 181 | func main() { 182 | a := alpha{ 183 | name: "test", 184 | } 185 | b := &beta{ 186 | alpha: a, 187 | } 188 | b.common(b) 189 | } 190 | ``` 191 | 192 | Результат в терминале: 193 | 194 | ```shell 195 | go run abstractClass/example3/program3.go 196 | common called 197 | work called 198 | Name is test 199 | ``` 200 | 201 | В ней: 202 | 203 | * Все методы по умолчанию принимают в качестве аргумента интерфейс `iAlpha`. Все 204 | неопределенные в структуре `alpha` методы будут вызываться, используя этот 205 | аргумент в методах по умолчанию. 206 | 207 | ## Заключение 208 | 209 | Приведенная выше программа удовлетворяет всем трём требованиям абстрактного 210 | класса. Это один из способов имитации абстрактного класса в Go. -------------------------------------------------------------------------------- /docs/compile-time_polymorphism.md: -------------------------------------------------------------------------------- 1 | # Полиморфизм во время компиляции в Go 2 | 3 | [Оригинал](https://golangbyexample.com/compile-time-polymorphism-go) 4 | 5 | При полиморфизме во время компиляции какую функцию вызывать решает компилятор. 6 | Примерами полиморфизма во время компиляции могут быть: 7 | * перегрузка метода/функции: существует более одного метода/функции с одним и 8 | тем же именем, но с разными сигнатурами или, возможно, с разными типами 9 | возвращаемых значений; 10 | * перегрузка операторов: один и тот же оператор используется для работы с 11 | разными типами данных. 12 | 13 | Go не поддерживает перегрузку метода. Это можно показать с помощью следующей 14 | программы: 15 | 16 | ```go 17 | package main 18 | 19 | import "fmt" 20 | 21 | type maths struct { 22 | } 23 | 24 | func (m *maths) add(a, b int) int { 25 | return a + b 26 | } 27 | 28 | func (m *maths) add(a, b, c int) int { 29 | return a + b + c 30 | } 31 | 32 | func main() { 33 | m := &maths{} 34 | fmt.Println(m.add(1, 2)) 35 | } 36 | ``` 37 | 38 | ```shell 39 | go run polymorphism/example1/program1.go 40 | polymorphism/example1/program1.go:12:6: method redeclared: maths.add 41 | method(*maths) func(int, int) int 42 | method(*maths) func(int, int, int) int 43 | polymorphism/example1/program1.go:12:17: (*maths).add redeclared in this block 44 | previous declaration at polymorphism/example1/program1.go:8:6 45 | ``` 46 | 47 | Go также не поддерживает перегрузку оператора. Причина указана в часто 48 | задаваемых вопросах - [https://golang.org/doc/faq#overloading](https://golang.org/doc/faq#overloading) 49 | 50 | > Вызов методов упрощается, если не требуется выполнять сопоставление типов. Опыт 51 | > работы с другими языками показал нам, что иногда полезно иметь различные 52 | > методы с одинаковыми именами, но с разными сигнатурами, но на практике это 53 | > сбивает с толку и ненадежно. Сопоставление только по имени и требование 54 | > согласованности типов было основным упрощающим решением в системе типов Go. 55 | > 56 | > Что касается перегрузки операторов, это кажется скорее удобством, чем 57 | > абсолютным требованием. Опять же, без него всё проще. 58 | 59 | Возникает вопрос: существует ли какая-нибудь альтернатива перегрузке методов в 60 | Go? Здесь на помощь приходят **вариативные функции**. Смотри программу ниже: 61 | 62 | ```go 63 | package main 64 | 65 | import "fmt" 66 | 67 | type maths struct { 68 | } 69 | 70 | func (m *maths) add(numbers ...int) int { 71 | result := 0 72 | for _, num := range numbers { 73 | result += num 74 | } 75 | return result 76 | } 77 | 78 | func main() { 79 | m := &maths{} 80 | 81 | fmt.Printf("Result: %d\n", m.add(2, 3)) 82 | fmt.Printf("Result: %d\n", m.add(2, 3, 4)) 83 | } 84 | ``` 85 | 86 | Результат в терминале: 87 | 88 | ```shell 89 | go run polymorphism/example2/program2.go 90 | Result: 5 91 | Result: 9 92 | ``` 93 | 94 | # Заключение 95 | 96 | Go не поддерживает напрямую перегрузку методов/функций/операторов, но вариативные 97 | функции позволяют достичь того же за счёт увеличения сложности кода. -------------------------------------------------------------------------------- /docs/encapsulation.md: -------------------------------------------------------------------------------- 1 | # Инкапсуляция в Go 2 | 3 | [Оригинал](https://golangbyexample.com/encapsulation-in-go/) 4 | 5 | Golang обеспечивает инкапсуляцию на уровне пакета. В Go нет ключевых слов 6 | `public`, `private` или `protected`. Единственный механизм управления 7 | видимостью — использование прописных и строчных букв. 8 | 9 | * Идентификаторы с прописной буквы экспортируются. Прописная буква означает, 10 | что это экспортируемый идентификатор. 11 | * Идентификаторы со строчной буквы не экспортируются. Строчные буквы 12 | указывают на то, что идентификатор не экспортируется и будет доступен 13 | только из того же пакета. 14 | 15 | Существует пять видов идентификаторов, которые можно экспортировать. 16 | 17 | 1. Структура 18 | 2. Метод структуры 19 | 3. Поле структуры 20 | 4. Функция 21 | 5. Переменная 22 | 23 | Посмотрим на пример, показывающий как экспортируются все вышеперечисленные 24 | идентификаторы. Файл называется `data.go`, а пакет - `model`. 25 | 26 | * Структура 27 | * Структура `Person` экспортируется 28 | * Структура `company` не экспортируется 29 | * Метод структуры 30 | * Метод структуры `Person` `GetAge()` экспортируется 31 | * Метод структуры `Person` `getName()` не экспортируется 32 | * Поле структуры 33 | * Поле структуры `Person` `Name` экспортируется 34 | * Поле структуры `Person` `age` не экспортируется 35 | * Функция 36 | * Функция `GetPerson()` экспортируется 37 | * Функция `getCompanyName()` не экспортируется 38 | * Переменные 39 | * Переменная `CompanyName` экспортируется 40 | * Переменная `companyLocation` не экспортируется 41 | 42 | **data.go** 43 | 44 | ```go 45 | package model 46 | 47 | import "fmt" 48 | 49 | var ( 50 | // CompanyName содержит название компании 51 | CompanyName = "test" 52 | companyLocation = "somecity" 53 | ) 54 | 55 | // Структура Person 56 | type Person struct { 57 | Name string 58 | age int 59 | } 60 | 61 | // GetAge возвращает возраст человека 62 | func (p *Person) GetAge() int { 63 | return p.age 64 | } 65 | 66 | func (p *Person) getName() string { 67 | return p.Name 68 | } 69 | 70 | type company struct { 71 | } 72 | 73 | // GetPerson возвращает объект Person 74 | func GetPerson() *Person { 75 | p := &Person{ 76 | Name: "test", 77 | age: 21, 78 | } 79 | fmt.Println("Model Package:") 80 | fmt.Println(p.Name) 81 | fmt.Println(p.age) 82 | return p 83 | } 84 | 85 | func getCompanyName() string { 86 | return CompanyName 87 | } 88 | ``` 89 | 90 | Давайте добавим файл `data_test.go` в пакет `model`. Ниже показано содержимое файла. 91 | 92 | **data_test.go** 93 | ```go 94 | package model 95 | 96 | import "fmt" 97 | 98 | // функция Test 99 | func Test() { 100 | // ИДЕНТИФИКАТОР СТРУКТУРЫ 101 | p := &Person{ 102 | Name: "test", 103 | age: 21, 104 | } 105 | fmt.Println(p) 106 | c := &company{} 107 | fmt.Println(c) 108 | 109 | // МЕТОД СТРУКТУРЫ 110 | fmt.Println(p.GetAge()) 111 | fmt.Println(p.getName()) 112 | 113 | // ПОЛЯ СТРУКТУРЫ 114 | fmt.Println(p.Name) 115 | fmt.Println(p.age) 116 | 117 | // ФУНКЦИЯ 118 | person2 := GetPerson() 119 | fmt.Println(person2) 120 | companyName := getCompanyName() 121 | fmt.Println(companyName) 122 | 123 | // ПЕРЕМЕННЫЕ 124 | fmt.Println(companyLocation) 125 | fmt.Println(CompanyName) 126 | } 127 | ``` 128 | 129 | При запуске этого файла он может получить доступ ко всем экспортированным и 130 | не экспортированным полям в `data.go`, поскольку оба находятся в одном и той же 131 | пакете `model`. Ошибок при компиляции не возникло и мы получаем следующий 132 | результат. 133 | 134 | Результат в терминале: 135 | 136 | ```shell 137 | go run main.go 138 | &{test 21} 139 | &{} 140 | 21 141 | test 142 | test 143 | 21 144 | Model Package: 145 | test 146 | 21 147 | &{test 21} 148 | test 149 | somecity 150 | test 151 | ``` 152 | 153 | Давайте переместим файл `data_test.go` в другой пакет `view`. Теперь обратите 154 | внимание на результат выполнения команды `go build`. Получаем ошибки компиляции. 155 | Все ошибки компиляции связаны с невозможностью ссылаться на неэкспортированные 156 | поля. 157 | 158 | ```go 159 | package view 160 | 161 | import ( 162 | "fmt" 163 | "github.com/MaksimDzhangirov/OOP-go/encapsulation/model" 164 | ) 165 | 166 | // функция Test 167 | func Test() { 168 | // ИДЕНТИФИКАТОР СТРУКТУРЫ 169 | p := &model.Person{ 170 | Name: "test", 171 | age: 21, 172 | } 173 | fmt.Println(p) 174 | c := &model.company{} 175 | fmt.Println(c) 176 | 177 | // МЕТОД СТРУКТУРЫ 178 | fmt.Println(p.GetAge()) 179 | fmt.Println(p.getName()) 180 | 181 | // ПОЛЯ СТРУКТУРЫ 182 | fmt.Println(p.Name) 183 | fmt.Println(p.age) 184 | 185 | // ФУНКЦИЯ 186 | person2 := model.GetPerson() 187 | fmt.Println(person2) 188 | companyName := model.getCompanyName() 189 | fmt.Println(companyName) 190 | 191 | // ПЕРЕМЕННЫЕ 192 | fmt.Println(model.companyLocation) 193 | fmt.Println(model.CompanyName) 194 | } 195 | ``` 196 | 197 | Результат в терминале: 198 | 199 | ```shell 200 | go build . 201 | view/test.go:13:3: cannot refer to unexported field 'age' in struct literal of type model.Person 202 | view/test.go:16:8: cannot refer to unexported name model.company 203 | view/test.go:21:15: p.getName undefined (cannot refer to unexported field or method model.(*Person).getName) 204 | view/test.go:25:15: p.age undefined (cannot refer to unexported field or method age) 205 | view/test.go:30:17: cannot refer to unexported name model.getCompanyName 206 | view/test.go:34:14: cannot refer to unexported name model.companyLocation 207 | ``` -------------------------------------------------------------------------------- /docs/inheritance.md: -------------------------------------------------------------------------------- 1 | # ООП: наследование в Golang 2 | 3 | [Оригинал](https://golangbyexample.com/oop-inheritance-golang-complete/) 4 | 5 | Мы попытаемся пояснить наследование в Go, сравнивая его с наследованием в Java. 6 | Первое о чём хотелось бы упомянуть здесь - в Golang нет таких ключевых слов как 7 | `extends` and `implements` в Java. Go предоставляет ограниченный функционал, 8 | присущий ключевым словам `extends` and `implements` по-разному, причём каждый 9 | имеет свои ограничения. Прежде чем мы начнём рассматривать наследование в Go 10 | стоит упомянуть, что: 11 | 12 | * в Go предпочтительнее использовать композицию вместо наследования. Это позволяет 13 | встраивать одну структуру в другую. 14 | * Go не поддерживает наследование типов. 15 | 16 | Начнем с простейшего примера наследования в Go. Затем перечислим ограничения или 17 | отсутствующий функционал. Затем мы попытаемся преодолеть ограничения или добавить 18 | недостающие функции, пока не напишем программу, которая будет обладать всеми 19 | свойствами наследования доступными в Go. Итак, начнём. 20 | 21 | Самый простой случай использования наследования — дочерний тип должен иметь 22 | доступ к полям и методам родительского типа. Это делается в Go посредством 23 | встраивания. Базовая структура встраивается в дочернюю, после чего 24 | базовые поля и методы могут быть напрямую доступы дочерней структуре. Смотри 25 | код ниже: дочерняя структура может напрямую обращаться к полю `color`, а также 26 | напрямую вызывать метод `say()`. 27 | 28 | ```go 29 | package main 30 | 31 | import "fmt" 32 | 33 | type base struct { 34 | color string 35 | } 36 | 37 | func (b *base) say() { 38 | fmt.Println("Hi from say function") 39 | } 40 | 41 | type child struct { 42 | base // встраиваем 43 | style string 44 | } 45 | 46 | func main() { 47 | base := base{color: "Red"} 48 | child := &child{ 49 | base: base, 50 | style: "somestyle", 51 | } 52 | child.say() 53 | fmt.Println("The color is " + child.color) 54 | } 55 | ``` 56 | 57 | Результат в терминале: 58 | 59 | ```shell 60 | go run inheritance/example1/program1.go 61 | Hi from say function 62 | The color is Red 63 | ``` 64 | 65 | Одним из ограничений вышеприведенной программы является то, что Вы не можете 66 | передать дочерний тип в функцию, которая ожидает базовый тип, поскольку Go не 67 | допускает наследования типов. Например, приведённый ниже код не компилируется 68 | и выдаёт ошибку - "**cannot use child (type *child) as type base in argument to 69 | check**". 70 | 71 | ```go 72 | package main 73 | 74 | import "fmt" 75 | 76 | type base struct { 77 | color string 78 | } 79 | 80 | func (b *base) say() { 81 | fmt.Println("Hi from say function") 82 | } 83 | 84 | type child struct { 85 | base // встраиваем 86 | style string 87 | } 88 | 89 | func check(b base) { 90 | b.say() 91 | } 92 | 93 | func main() { 94 | base := base{color: "Red"} 95 | child := &child{ 96 | base: base, 97 | style: "somestyle", 98 | } 99 | child.say() 100 | fmt.Println("The color is " + child.color) 101 | check(child) 102 | } 103 | ``` 104 | 105 | Результат в терминале: 106 | 107 | ```shell 108 | go run inheritance/example2/program2.go 109 | inheritance/example2/program2.go:30:7: cannot use child (type *child) as type base in argument to check 110 | ``` 111 | 112 | Вышеприведенная ошибка говорит о том, что дочерний тип не может быть задан в Go 113 | просто с помощью встраивания. Попробуем исправить эту ошибку. Для этого нам 114 | необходимо использовать интерфейсы Go. Смотри показанную ниже версию программы, 115 | в которой исправлена эта ошибка. 116 | 117 | ```go 118 | package main 119 | 120 | import "fmt" 121 | 122 | type iBase interface { 123 | say() 124 | } 125 | 126 | type base struct { 127 | color string 128 | } 129 | 130 | func (b *base) say() { 131 | fmt.Println("Hi from say function") 132 | } 133 | 134 | type child struct { 135 | base // встраиваем 136 | style string 137 | } 138 | 139 | func check(b iBase) { 140 | b.say() 141 | } 142 | 143 | func main() { 144 | base := base{color: "Red"} 145 | child := &child{ 146 | base: base, 147 | style: "somestyle", 148 | } 149 | child.say() 150 | fmt.Println("The color is " + child.color) 151 | check(child) 152 | } 153 | ``` 154 | 155 | Результат в терминале: 156 | 157 | ```shell 158 | go run inheritance/example3/program3.go 159 | Hi from say function 160 | The color is Red 161 | Hi from say function 162 | ``` 163 | 164 | В приведенной выше программе мы: (a) создали интерфейс `iBase`, который 165 | содержит метод `say`; (b) изменили метод «check», чтобы он принимал в качестве 166 | аргумента тип `iBase`. 167 | 168 | Поскольку базовая структура реализует метод `say`, а в дочернюю структуру в 169 | свою очередь встраивается базовая, то дочерняя структура косвенно реализует 170 | метод `say` и становится типа `iBase`. Из-за этого теперь мы можем передать её 171 | в функцию `check`. Отлично, мы устранили одно ограничение, скомбинировав 172 | структуру и интерфейс. 173 | 174 | Но существует ещё одно ограничение. Допустим у базовой и дочерней структуры 175 | есть ещё один метод `clear`, а метод `say` вызывает метод `clear`. Затем 176 | когда метод `say` вызывается в дочерней структуре, он запускает метод `clear` 177 | базового, а не дочернего объекта. Смотри пример ниже. 178 | 179 | ```go 180 | package main 181 | 182 | import "fmt" 183 | 184 | type iBase interface { 185 | say() 186 | } 187 | 188 | type base struct { 189 | color string 190 | } 191 | 192 | func (b *base) say() { 193 | b.clear() 194 | } 195 | 196 | func (b *base) clear() { 197 | fmt.Println("Clear from base's function") 198 | } 199 | 200 | type child struct { 201 | base // встраиваем 202 | style string 203 | } 204 | 205 | func (c *child) clear() { 206 | fmt.Println("Clear from child's function") 207 | } 208 | 209 | func check(b iBase) { 210 | b.say() 211 | } 212 | 213 | func main() { 214 | base := base{color: "Red"} 215 | child := &child{ 216 | base: base, 217 | style: "somestyle", 218 | } 219 | child.say() 220 | } 221 | ``` 222 | 223 | Результат в терминале: 224 | 225 | ```shell 226 | go run inheritance/example4/program4.go 227 | Clear from base's function 228 | ``` 229 | 230 | Как видите, вместо дочернего метода вызывается базовый метод `clear`. Это поведение 231 | отличается от того, что происходит в Java, где был бы вызван метод `clear` 232 | объекта `child`. 233 | 234 | Один из способов решить указанную выше проблему — сделать `clear` полем в базовой 235 | структуру типа `function`. Это возможно в Go, поскольку в нём функции являются 236 | объектами первого класса. Ниже показано решение. 237 | 238 | ```go 239 | package main 240 | 241 | import "fmt" 242 | 243 | type iBase interface { 244 | say() 245 | } 246 | type base struct { 247 | color string 248 | clear func() 249 | } 250 | func (b *base) say() { 251 | b.clear() 252 | } 253 | type child struct { 254 | base //embedding 255 | style string 256 | } 257 | func check(b iBase) { 258 | b.say() 259 | } 260 | func main() { 261 | base := base{color: "Red", 262 | clear: func() { 263 | fmt.Println("Clear from child's function") 264 | }} 265 | child := &child{ 266 | base: base, 267 | style: "somestyle", 268 | } 269 | child.say() 270 | } 271 | ``` 272 | 273 | Результат в терминале: 274 | 275 | ```shell 276 | go run inheritance/example5/program5.go 277 | Clear from child's function 278 | ``` 279 | 280 | Давайте попробуем добавить ещё один функционал в вышеприведенную программу, а 281 | именно: 282 | 283 | Множественное наследование — дочерняя структура должна иметь доступ к полям и 284 | методам двух базовых структур, а также должна быть возможна подтипизация. Вот 285 | пример такого кода: 286 | 287 | ```go 288 | package main 289 | 290 | import "fmt" 291 | 292 | type iBase1 interface { 293 | say() 294 | } 295 | 296 | type iBase2 interface { 297 | walk() 298 | } 299 | 300 | type base1 struct { 301 | color string 302 | } 303 | 304 | func (b *base1) say() { 305 | fmt.Println("Hi from say function") 306 | } 307 | 308 | type base2 struct { 309 | } 310 | 311 | func (b *base1) walk() { 312 | fmt.Println("Hi from walk function") 313 | } 314 | 315 | type child struct { 316 | base1 // встраиваем 317 | base2 // встраиваем 318 | style string 319 | } 320 | 321 | func check1(b iBase1) { 322 | b.say() 323 | } 324 | 325 | func check2(b iBase2) { 326 | b.walk() 327 | } 328 | 329 | func main() { 330 | base1 := base1{ 331 | color: "Red", 332 | } 333 | base2 := base2{} 334 | child := &child{ 335 | base1: base1, 336 | base2: base2, 337 | style: "somestyle", 338 | } 339 | child.say() 340 | child.walk() 341 | check1(child) 342 | check2(child) 343 | } 344 | ``` 345 | 346 | Результат в терминале: 347 | 348 | ```shell 349 | go run inheritance/example6/program6.go 350 | Hi from say function 351 | Hi from walk function 352 | Hi from say function 353 | Hi from walk function 354 | ``` 355 | 356 | В вышеприведенной программе в дочернюю структуру встраивается как `base1`, так и 357 | `base2`. Его также можно передать как экземпляр интерфейса `iBase1` и `iBase2` 358 | функциям `check1` и `check2` соответственно. Так мы добиваемся множественного 359 | наследования. 360 | 361 | Теперь главный вопрос как реализовать "Иерархию типов" в Go. Как уже было сказано 362 | выше, наследование типов не допускается и, следовательно, в Go нет иерархии типов. 363 | В Go намеренно это не реализовано, поэтому любое изменение в поведении 364 | интерфейса распространяется только на те структуры, которые ему удовлетворяют. 365 | 366 | Тем не менее, мы можем реализовать иерархию типов, используя интерфейсы и 367 | структуру, как показано ниже. 368 | 369 | ```go 370 | package main 371 | import "fmt" 372 | type iAnimal interface { 373 | breathe() 374 | } 375 | type animal struct { 376 | } 377 | func (a *animal) breathe() { 378 | fmt.Println("Animal breate") 379 | } 380 | type iAquatic interface { 381 | iAnimal 382 | swim() 383 | } 384 | type aquatic struct { 385 | animal 386 | } 387 | func (a *aquatic) swim() { 388 | fmt.Println("Aquatic swim") 389 | } 390 | type iNonAquatic interface { 391 | iAnimal 392 | walk() 393 | } 394 | type nonAquatic struct { 395 | animal 396 | } 397 | func (a *nonAquatic) walk() { 398 | fmt.Println("Non-Aquatic walk") 399 | } 400 | type shark struct { 401 | aquatic 402 | } 403 | type lion struct { 404 | nonAquatic 405 | } 406 | func main() { 407 | shark := &shark{} 408 | checkAquatic(shark) 409 | checkAnimal(shark) 410 | lion := &lion{} 411 | checkNonAquatic(lion) 412 | checkAnimal(lion) 413 | } 414 | func checkAquatic(a iAquatic) {} 415 | func checkNonAquatic(a iNonAquatic) {} 416 | func checkAnimal(a iAnimal) {} 417 | ``` 418 | 419 | Посмотрите как в вышеприведенной программе мы смогли создать иерархию. Это 420 | характерный для Go способ создания иерархии типов с использованием встраивания как 421 | на уровне структуры, так и на уровне интерфейса. Здесь следует отметить, что 422 | если нужно различать типы, то есть `shark` не должна быть одновременно `iAquatic` 423 | и `iNonAquatic`, тогда должен быть хотя бы один метод в наборе методов `iAquatic` 424 | и `iNonAquatic`, которого нет в другом. В нашем примере такими методами 425 | являются `swim` и `walk`. 426 | 427 | Результат в терминале: 428 | 429 | ```shell 430 | go run inheritance/example7/program7.go 431 | iAnimal 432 | --iAquatic 433 | ----shark 434 | --iNonAquatic 435 | ----lion 436 | ``` 437 | 438 | ## Заключение 439 | 440 | Go не поддерживает наследование типов, но того же можно добиться с помощью 441 | встраивания, но нужно быть внимательным при создании такой иерархии типов. 442 | Кроме того, Go не поддерживает переопределение метода. 443 | -------------------------------------------------------------------------------- /docs/polymorphism.md: -------------------------------------------------------------------------------- 1 | # ООП: полиморфизм в Golang 2 | 3 | [Оригинал](https://golangbyexample.com/oop-polymorphism-in-go-complete-guide/) 4 | 5 | Прежде, чем перейти к примерам, давайте дадим определение полиморфизму. 6 | 7 | "Существование чего-либо в различных формах" 8 | 9 | В программировании также бывают такие ситуации, когда поведение одинаково в 10 | разных контекстах. По-хорошему такое поведение должно называться одинаково. Именно 11 | здесь полиморфизм проявляется в контексте программирования. С точки зрения 12 | программирования возможны два типа полиморфизма: 13 | 14 | * Полиморфизм во время компиляции (Compile Time Polymorphism) - в этом случае 15 | компилятор знает какие именно функции будут выполняться для конкретного 16 | вызова. Примером полиморфизма во время компиляции являются: 17 | * перегрузка функции — одно и то же имя функции с разными аргументами 18 | * перегрузка операторов 19 | * Полиморфизм во время выполнения (Run Time Polymorphism) - в этом случае 20 | функция, которая должна быть вызвана, определяется во время выполнения. 21 | 22 | Давайте рассмотрим какие типы полиморфизма во времени компиляции и выполнения 23 | возможны в Go. 24 | 25 | * [Полиморфизм во время компиляции в Go](compile-time_polymorphism.md) 26 | * [Полиморфизм во время выполнения в Go](run-time_polymorphism.md) 27 | 28 | # Заключение 29 | 30 | Если вы прочитали две вышеупомянутые статьи, то поняли, что полиморфизм во 31 | время компиляции в GoLang невозможен. Доступен только полиморфизм времени 32 | выполнения. Полиморфизм во времени выполнения достигается в Go с помощью 33 | интерфейсов. 34 | 35 | -------------------------------------------------------------------------------- /docs/run-time_polymorphism.md: -------------------------------------------------------------------------------- 1 | # Полиморфизм во время выполнения в Go 2 | 3 | [Оригинал](https://golangbyexample.com/runtime-polymorphism-go/) 4 | 5 | Полиморфизм во время выполнения означает, что решение о том какую функцию вызывать 6 | принимается во время выполнения. 7 | 8 | Давайте разберём этот момент на примере. В разных странах по-разному рассчитывается 9 | налог. Это поведение можно представить с помощью интерфейса. 10 | 11 | ```go 12 | type taxCalculator interface { 13 | calculateTax() 14 | } 15 | ``` 16 | 17 | Теперь у разных стран может быть различная структура, но все они будут реализовывать 18 | метод `calculateTax()`. Например, структура `indianTax` показана ниже. В ней также 19 | может быть определен метод `calculateTax()`, который будет выполнять реальные 20 | вычисления, используя проценты. 21 | 22 | Точно так же налоговые системы других стран могут быть представлены структурой, 23 | и они также будут реализовывать свой собственный метод `calculateTax()` для 24 | определения значения налога. 25 | 26 | Теперь давайте посмотрим, как мы можем использовать этот интерфейс `taxCalcuator` 27 | для расчета налога с лиц, проживающих в разных странах в различное время года. 28 | Код всей программы показан ниже: 29 | 30 | ```go 31 | package main 32 | 33 | import "fmt" 34 | 35 | type taxSystem interface { 36 | calculateTax() int 37 | } 38 | 39 | type indianTax struct { 40 | taxPercentage int 41 | income int 42 | } 43 | 44 | func (i *indianTax) calculateTax() int { 45 | tax := i.income * i.taxPercentage / 100 46 | return tax 47 | } 48 | 49 | type singaporeTax struct { 50 | taxPercentage int 51 | income int 52 | } 53 | 54 | func (i *singaporeTax) calculateTax() int { 55 | tax := i.income * i.taxPercentage / 100 56 | return tax 57 | } 58 | 59 | type usaTax struct { 60 | taxPercentage int 61 | income int 62 | } 63 | 64 | func (i *usaTax) calculateTax() int { 65 | tax := i.income * i.taxPercentage / 100 66 | return tax 67 | } 68 | 69 | func main() { 70 | indianTax := &indianTax{ 71 | taxPercentage: 30, 72 | income: 1000, 73 | } 74 | singaporeTax := &singaporeTax{ 75 | taxPercentage: 10, 76 | income: 2000, 77 | } 78 | taxSystems := []taxSystem{indianTax, singaporeTax} 79 | totalTax := calculateTotalTax(taxSystems) 80 | 81 | fmt.Printf("Total Tax is %d\n", totalTax) 82 | } 83 | 84 | func calculateTotalTax(taxSystems []taxSystem) int { 85 | totalTax := 0 86 | for _, t := range taxSystems { 87 | totalTax += t.calculateTax() // вот где происходит полиморфизм во время выполнения 88 | } 89 | return totalTax 90 | } 91 | ``` 92 | 93 | Результат в терминале: 94 | 95 | ```shell 96 | go run polymorphism/example3/program3.go 97 | Total Tax is 500 98 | ``` 99 | 100 | Ниже приведена строка, где происходит полиморфизм во время выполнения. 101 | 102 | ```go 103 | totalTax += t.calculateTax() // вот где происходит полиморфизм во время выполнения 104 | ``` 105 | 106 | Один и тот же метод calculateTax используется в различных контекстах для расчёта 107 | налога. Когда компилятор видит такой вызов, он откладывает решение о том какой 108 | метод будет вызван до времени выполнения. Это то, что происходит под капотом. 109 | 110 | ## Добавляем налоговые системы: 111 | 112 | Теперь давайте расширим вышеприведенную программу, включив в нее налоговую 113 | систему для США. 114 | 115 | ```go 116 | type usaTax struct { 117 | taxPercentage int 118 | income int 119 | } 120 | 121 | func (i *usaTax) calculateTax() int { 122 | tax := i.income * i.taxPercentage / 100 123 | return tax 124 | } 125 | ``` 126 | 127 | Нам достаточно изменить функцию main, чтобы добавить налоговую систему США. 128 | 129 | ```go 130 | func main() { 131 | indianTax := &indianTax{ 132 | taxPercentage: 30, 133 | income: 1000, 134 | } 135 | singaporeTax := &singaporeTax{ 136 | taxPercentage: 10, 137 | income: 2000, 138 | } 139 | usaTax := &usaTax{ 140 | taxPercentage: 40, 141 | income: 500, 142 | } 143 | taxSystems := []taxSystem{indianTax, singaporeTax, usaTax} 144 | totalTax := calculateTotalTax(taxSystems) 145 | 146 | fmt.Printf("Total Tax is %d\n", totalTax) 147 | } 148 | ``` 149 | 150 | Результат в терминале: 151 | 152 | ```shell 153 | go run polymorphism/example3/program3.go 154 | Total Tax is 700 155 | ``` 156 | 157 | Как вы возможно заметили изменять функцию calculateTotalTax в вышеприведенной 158 | программе не нужно, чтобы учесть налоговую систему США. В этом заключается 159 | преимущество использования интерфейсов и полиморфизма. -------------------------------------------------------------------------------- /encapsulation/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/MaksimDzhangirov/OOP-go/encapsulation/view" 5 | ) 6 | 7 | func main() { 8 | view.Test() 9 | } 10 | -------------------------------------------------------------------------------- /encapsulation/model/data.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "fmt" 4 | 5 | var ( 6 | // CompanyName содержит название компании 7 | CompanyName = "test" 8 | companyLocation = "somecity" 9 | ) 10 | 11 | // Структура Person 12 | type Person struct { 13 | Name string 14 | age int 15 | } 16 | 17 | // GetAge возвращает возраст человека 18 | func (p *Person) GetAge() int { 19 | return p.age 20 | } 21 | 22 | func (p *Person) getName() string { 23 | return p.Name 24 | } 25 | 26 | type company struct { 27 | } 28 | 29 | // GetPerson возвращает объект Person 30 | func GetPerson() *Person { 31 | p := &Person{ 32 | Name: "test", 33 | age: 21, 34 | } 35 | fmt.Println("Model Package:") 36 | fmt.Println(p.Name) 37 | fmt.Println(p.age) 38 | return p 39 | } 40 | 41 | func getCompanyName() string { 42 | return CompanyName 43 | } 44 | -------------------------------------------------------------------------------- /encapsulation/view/test.go: -------------------------------------------------------------------------------- 1 | package view 2 | 3 | import ( 4 | "fmt" 5 | "github.com/MaksimDzhangirov/OOP-go/encapsulation/model" 6 | ) 7 | 8 | // функция Test 9 | func Test() { 10 | // ИДЕНТИФИКАТОР СТРУКТУРЫ 11 | p := &model.Person{ 12 | Name: "test", 13 | age: 21, 14 | } 15 | fmt.Println(p) 16 | c := &model.company{} 17 | fmt.Println(c) 18 | 19 | // МЕТОД СТРУКТУРЫ 20 | fmt.Println(p.GetAge()) 21 | fmt.Println(p.getName()) 22 | 23 | // ПОЛЯ СТРУКТУРЫ 24 | fmt.Println(p.Name) 25 | fmt.Println(p.age) 26 | 27 | // ФУНКЦИЯ 28 | person2 := model.GetPerson() 29 | fmt.Println(person2) 30 | companyName := model.getCompanyName() 31 | fmt.Println(companyName) 32 | 33 | // ПЕРЕМЕННЫЕ 34 | fmt.Println(model.companyLocation) 35 | fmt.Println(model.CompanyName) 36 | } -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/MaksimDzhangirov/OOP-go 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /inheritance/example1/program1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type base struct { 6 | color string 7 | } 8 | 9 | func (b *base) say() { 10 | fmt.Println("Hi from say function") 11 | } 12 | 13 | type child struct { 14 | base // встраиваем 15 | style string 16 | } 17 | 18 | func main() { 19 | base := base{color: "Red"} 20 | child := &child{ 21 | base: base, 22 | style: "somestyle", 23 | } 24 | child.say() 25 | fmt.Println("The color is " + child.color) 26 | } 27 | -------------------------------------------------------------------------------- /inheritance/example2/program2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type base struct { 6 | color string 7 | } 8 | 9 | func (b *base) say() { 10 | fmt.Println("Hi from say function") 11 | } 12 | 13 | type child struct { 14 | base // встраиваем 15 | style string 16 | } 17 | 18 | func check(b base) { 19 | b.say() 20 | } 21 | 22 | func main() { 23 | base := base{color: "Red"} 24 | child := &child{ 25 | base: base, 26 | style: "somestyle", 27 | } 28 | child.say() 29 | fmt.Println("The color is " + child.color) 30 | check(child) 31 | } 32 | -------------------------------------------------------------------------------- /inheritance/example3/program3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type iBase interface { 6 | say() 7 | } 8 | 9 | type base struct { 10 | color string 11 | } 12 | 13 | func (b *base) say() { 14 | fmt.Println("Hi from say function") 15 | } 16 | 17 | type child struct { 18 | base // встраиваем 19 | style string 20 | } 21 | 22 | func check(b iBase) { 23 | b.say() 24 | } 25 | 26 | func main() { 27 | base := base{color: "Red"} 28 | child := &child{ 29 | base: base, 30 | style: "somestyle", 31 | } 32 | child.say() 33 | fmt.Println("The color is " + child.color) 34 | check(child) 35 | } 36 | -------------------------------------------------------------------------------- /inheritance/example4/program4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type iBase interface { 6 | say() 7 | } 8 | 9 | type base struct { 10 | color string 11 | } 12 | 13 | func (b *base) say() { 14 | b.clear() 15 | } 16 | 17 | func (b *base) clear() { 18 | fmt.Println("Clear from base's function") 19 | } 20 | 21 | type child struct { 22 | base // встраиваем 23 | style string 24 | } 25 | 26 | func (c *child) clear() { 27 | fmt.Println("Clear from child's function") 28 | } 29 | 30 | func check(b iBase) { 31 | b.say() 32 | } 33 | 34 | func main() { 35 | base := base{color: "Red"} 36 | child := &child{ 37 | base: base, 38 | style: "somestyle", 39 | } 40 | child.say() 41 | } 42 | -------------------------------------------------------------------------------- /inheritance/example5/program5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type iBase interface { 6 | say() 7 | } 8 | 9 | type base struct { 10 | color string 11 | clear func() 12 | } 13 | 14 | func (b *base) say() { 15 | b.clear() 16 | } 17 | 18 | type child struct { 19 | base // встраиваем 20 | style string 21 | } 22 | 23 | func check(b iBase) { 24 | b.say() 25 | } 26 | 27 | func main() { 28 | base := base{ 29 | color: "Red", 30 | clear: func() { 31 | fmt.Println("Clear from child's function") 32 | }, 33 | } 34 | child := &child{ 35 | base: base, 36 | style: "somestyle", 37 | } 38 | child.say() 39 | } 40 | -------------------------------------------------------------------------------- /inheritance/example6/program6.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type iBase1 interface { 6 | say() 7 | } 8 | 9 | type iBase2 interface { 10 | walk() 11 | } 12 | 13 | type base1 struct { 14 | color string 15 | } 16 | 17 | func (b *base1) say() { 18 | fmt.Println("Hi from say function") 19 | } 20 | 21 | type base2 struct { 22 | } 23 | 24 | func (b *base1) walk() { 25 | fmt.Println("Hi from walk function") 26 | } 27 | 28 | type child struct { 29 | base1 // встраиваем 30 | base2 // встраиваем 31 | style string 32 | } 33 | 34 | func check1(b iBase1) { 35 | b.say() 36 | } 37 | 38 | func check2(b iBase2) { 39 | b.walk() 40 | } 41 | 42 | func main() { 43 | base1 := base1{ 44 | color: "Red", 45 | } 46 | base2 := base2{} 47 | child := &child{ 48 | base1: base1, 49 | base2: base2, 50 | style: "somestyle", 51 | } 52 | child.say() 53 | child.walk() 54 | check1(child) 55 | check2(child) 56 | } 57 | -------------------------------------------------------------------------------- /polymorphism/example1/program1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type maths struct { 6 | } 7 | 8 | func (m *maths) add(a, b int) int { 9 | return a + b 10 | } 11 | 12 | //func (m *maths) add(a, b, c int) int { 13 | // return a + b + c 14 | //} 15 | 16 | func main() { 17 | m := &maths{} 18 | fmt.Println(m.add(1, 2)) 19 | } 20 | -------------------------------------------------------------------------------- /polymorphism/example2/program2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type maths struct { 6 | } 7 | 8 | func (m *maths) add(numbers ...int) int { 9 | result := 0 10 | for _, num := range numbers { 11 | result += num 12 | } 13 | return result 14 | } 15 | 16 | func main() { 17 | m := &maths{} 18 | 19 | fmt.Printf("Result: %d\n", m.add(2, 3)) 20 | fmt.Printf("Result: %d\n", m.add(2, 3, 4)) 21 | } 22 | -------------------------------------------------------------------------------- /polymorphism/example3/program3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type taxSystem interface { 6 | calculateTax() int 7 | } 8 | 9 | type indianTax struct { 10 | taxPercentage int 11 | income int 12 | } 13 | 14 | func (i *indianTax) calculateTax() int { 15 | tax := i.income * i.taxPercentage / 100 16 | return tax 17 | } 18 | 19 | type singaporeTax struct { 20 | taxPercentage int 21 | income int 22 | } 23 | 24 | func (i *singaporeTax) calculateTax() int { 25 | tax := i.income * i.taxPercentage / 100 26 | return tax 27 | } 28 | 29 | type usaTax struct { 30 | taxPercentage int 31 | income int 32 | } 33 | 34 | func (i *usaTax) calculateTax() int { 35 | tax := i.income * i.taxPercentage / 100 36 | return tax 37 | } 38 | 39 | func main() { 40 | indianTax := &indianTax{ 41 | taxPercentage: 30, 42 | income: 1000, 43 | } 44 | singaporeTax := &singaporeTax{ 45 | taxPercentage: 10, 46 | income: 2000, 47 | } 48 | usaTax := &usaTax{ 49 | taxPercentage: 40, 50 | income: 500, 51 | } 52 | taxSystems := []taxSystem{indianTax, singaporeTax, usaTax} 53 | totalTax := calculateTotalTax(taxSystems) 54 | 55 | fmt.Printf("Total Tax is %d\n", totalTax) 56 | } 57 | 58 | func calculateTotalTax(taxSystems []taxSystem) int { 59 | totalTax := 0 60 | for _, t := range taxSystems { 61 | totalTax += t.calculateTax() // вот где происходит полиморфизм во время выполнения 62 | } 63 | return totalTax 64 | } 65 | --------------------------------------------------------------------------------