|
| 1 | +# Nesne-Yönelim |
| 2 | + |
| 3 | +Son iki bölüm de fonksiyonlar ve `struct` hakkında konuştuk, ancak fonksiyonları `struct` ın bir alanı olarak kullanmayı düşündünüz mü? Bu bölümde, alıcısı olan `method` olarak adlandırılan başka bir fonksiyon biçimi tanıtacağım. |
| 4 | + |
| 5 | +## method |
| 6 | + |
| 7 | +Bir "Dikdortgen" struct tanımladığınızı ve onun alanını hesaplamak istediğinizi varsayalım. Bu amaca ulaşmak için genellikle aşağıdaki kodu kullanırdık. |
| 8 | +```Go |
| 9 | +package main |
| 10 | + |
| 11 | +import "fmt" |
| 12 | + |
| 13 | +type Dikdortgen struct { |
| 14 | + genislik, yukseklik float64 |
| 15 | +} |
| 16 | + |
| 17 | +func alan(d Dikdortgen) float64 { |
| 18 | + return d.genislik * d.yukseklik |
| 19 | +} |
| 20 | + |
| 21 | +func main() { |
| 22 | + d1 := Dikdortgen{12, 2} |
| 23 | + d2 := Dikdortgen{9, 4} |
| 24 | + fmt.Println("d1 in alanı: ", alan(d1)) |
| 25 | + fmt.Println("d2 nin alanı: ", alan(d2)) |
| 26 | +} |
| 27 | + |
| 28 | +``` |
| 29 | +Yukarıdaki örnek bir Dikdortgen'in alanını hesaplayabilir. Burada `alan` isimli fonksiyonu kullanıyoruz, fakat bu fonksiyon Dikdortgen struct'ının bir method u değil(klasik nesne yönelimli dillerdeki sınıf nethodları gibi). Fark edebileceğiniz gibi fonksiyon ve struct iki bağımsız şeydir. |
| 30 | + |
| 31 | +Şimdiye kadar sorun değil. Bununla birlikte, bir dairenin, karenin, beşgenin veya başka herhangi bir şeklin alanını da hesaplamanız gerekiyorsa, çok benzer adlara sahip ek fonksiyonlar eklemeniz gerekecektir. |
| 32 | + |
| 33 | + |
| 34 | + |
| 35 | +Şekil 2.8 Fonksiyon ve struct arasındaki ilişki |
| 36 | + |
| 37 | +Açıkçası bu hiç hoş değil. Ayrıca, alan fonksiyonu bir dairenin veya dikdörtgenin özelliği olmalıdır. |
| 38 | + |
| 39 | +İşte `method` un devreye gireceği nokta burasıdır. `method`, bir türe/tipe bağlı fonksiyondur. `func` anahtar sözcüğünün, bu methodun ana gövdesi olan `receiver` adlı bit parametreye sahip olması haricinde, fonksiyonlara benzer bir sözdizimi vardır. |
| 40 | + |
| 41 | +Aynı örneği kullanarak, `Dikdortgen.Alan()` çevresel bir fonksiyon olması yerine doğrudan Dikdortgen'e ait bir methoddur. Daha spesifik olarak, `yukseklik`, `genislik` ve `Alan()` hepsi Dikdortgen'e aittir. |
| 42 | + |
| 43 | +Rob Pike'ın dediği gibi. |
| 44 | + |
| 45 | + "Bir method, alıcı olarak adlandırılan ilk örtülü argüman olan bir fonksiyondur." |
| 46 | + |
| 47 | +method sözdimi. |
| 48 | +```Go |
| 49 | +func (r ReceiverType) funcName(parameters) (results) |
| 50 | +``` |
| 51 | +Örneğimizi `method` kullanarak değiştirelim. |
| 52 | +```Go |
| 53 | +package main |
| 54 | + |
| 55 | +import ( |
| 56 | + "fmt" |
| 57 | + "math" |
| 58 | +) |
| 59 | + |
| 60 | +type Daire struct { |
| 61 | + yaricap float64 |
| 62 | +} |
| 63 | + |
| 64 | +type Dikdortgen struct { |
| 65 | + genislik, yukseklik float64 |
| 66 | +} |
| 67 | + |
| 68 | +// method |
| 69 | +func (daire Daire) Alan() float64 { |
| 70 | + return daire.yaricap * daire.yaricap * math.Pi |
| 71 | +} |
| 72 | + |
| 73 | +// method |
| 74 | +func (dikdortgen Dikdortgen) Alan() float64 { |
| 75 | + return dikdortgen.genislik * dikdortgen.yukseklik |
| 76 | +} |
| 77 | + |
| 78 | +func main() { |
| 79 | + daire1 := Daire{10} |
| 80 | + daire2 := Daire{25} |
| 81 | + dikdortgen1 := Dikdortgen{9, 4} |
| 82 | + dikdortgen2 := Dikdortgen{12, 2} |
| 83 | + |
| 84 | + fmt.Println("daire1 in alanı: ", daire1.Alan()) |
| 85 | + fmt.Println("daire2 nin alanı: ", daire2.Alan()) |
| 86 | + fmt.Println("dikdortgen1 in alanı: ", dikdortgen1.Alan()) |
| 87 | + fmt.Println("dikdortgen2 nin alanı: ", dikdortgen2.Alan()) |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +Methodları kullanma notları. |
| 92 | + |
| 93 | +- Methodların adı aynıysa ancak aynı alıcıları paylaşmıyorlarsa, aynı değildirler. |
| 94 | +- Methodlar alıcılardaki alanlara erişebilirler. |
| 95 | +- Bir `struct` da method çağırmak için `.` kullanın, aynı şekilde alanları da çağırabilirsiniz. |
| 96 | + |
| 97 | + |
| 98 | + |
| 99 | +Şekil 2.9 Methodlar farklı struct larda farklıdırlar. |
| 100 | + |
| 101 | +Yukarıdaki örnekte Alan() methodu hem Dikdortgen hem de Daire'de mevcuttur, bu nedenle alıcıları Dikdortgen ve Daire'dir. |
| 102 | + |
| 103 | +Önemsiz bir detay olarak bir method noktalı çizgi ile kullanılmışsa anlamı alıcıya referans olarak değil değer olarak geçirilmiştir demektir. Aralarındaki fark, bir methodun, alıcısı referansla geçildiğinde alıcının değerlerini değiştirebilmesi ve değer olarak geçildiğinde ise alıcının bir kopyasını almasıdır. |
| 104 | + |
| 105 | +Alıcı sadece bir struct'mı olmalıdır? Tabii ki değil. Herhangibir tür/tip methodun alıcısı olabilir. Özelleştirilmiş türler/tipler hakkında kafanız karışabilir. struct özel bir tür/tip dir - daha birçok özelleştirilmiş tür/tip yer almaktadır. |
| 106 | + |
| 107 | +Özelleştirilmiş bir tür/tip tanımlamak için aşağıdaki formatı kullanın. |
| 108 | +```Go |
| 109 | +type typeName typeLiteral |
| 110 | +``` |
| 111 | +Özelleştirilmiş türler/tipler e örnekler: |
| 112 | + |
| 113 | +```Go |
| 114 | +type yas int |
| 115 | +type fiyat float32 |
| 116 | +type aylar map[string]int |
| 117 | + |
| 118 | +a := aylar { |
| 119 | + "Ocak":31, |
| 120 | + "Şubat":28, |
| 121 | + ... |
| 122 | + "Aralık":31, |
| 123 | +} |
| 124 | +``` |
| 125 | + |
| 126 | +Özelleştirilmiş türlerin/tiplerin artık nasıl kullanılacağını biliyorsunuz. C programlama dilindeki `typedef` ifadesine benzer bir şekilde, yukarıdaki örnekte `int` yerine `yas` kullanıyoruz. |
| 127 | + |
| 128 | +`method` hakkında konuşmaya geri dönelim. |
| 129 | + |
| 130 | +Özelleştirilmiş türler/tipler de istediğiniz kadar method kullanabilirsiniz. |
| 131 | +```Go |
| 132 | +package main |
| 133 | + |
| 134 | +import "fmt" |
| 135 | + |
| 136 | +const ( |
| 137 | + BEYAZ = iota |
| 138 | + SIYAH |
| 139 | + MAVI |
| 140 | + KIRMIZI |
| 141 | + SARI |
| 142 | +) |
| 143 | + |
| 144 | +type Kutu struct { |
| 145 | + genislik, yukseklik, derinlik float64 |
| 146 | + renk Renk |
| 147 | +} |
| 148 | +type Renk byte |
| 149 | +type KutuListesi []Kutu //kutu listesi |
| 150 | + |
| 151 | +// method |
| 152 | +func (kutu Kutu) Hacim() float64 { |
| 153 | + return kutu.genislik * kutu.yukseklik * kutu.derinlik |
| 154 | +} |
| 155 | + |
| 156 | +// işaretçi alıcılı method |
| 157 | +func (k *Kutu) RenkAta(r Renk) { |
| 158 | + k.renk = r |
| 159 | +} |
| 160 | + |
| 161 | +// method |
| 162 | +func (kl KutuListesi) EnBuyuklerininRengi() Color { |
| 163 | + h := 0.00 |
| 164 | + r := Renk(BEYAZ) |
| 165 | + for _, k := range kl { |
| 166 | + if k.Hacim() > h { |
| 167 | + h = k.Hacim() |
| 168 | + r = k.renk |
| 169 | + } |
| 170 | + } |
| 171 | + return k |
| 172 | +} |
| 173 | + |
| 174 | +// method |
| 175 | +func (kl KutuListesi) SiyahaBoya() { |
| 176 | + for i, _ := range kl { |
| 177 | + kl[i].RenkAta(SIYAH) |
| 178 | + } |
| 179 | +} |
| 180 | + |
| 181 | +// method |
| 182 | +func (r Renk) String() string { |
| 183 | + strings := []string{"BEYAZ", "SIYAH", "MAVI", "KIRMIZI", "SARI"} |
| 184 | + return strings[r] |
| 185 | +} |
| 186 | + |
| 187 | +func main() { |
| 188 | + kutular := KutuListesi{ |
| 189 | + Kutu{4, 4, 4, KIRMIZI}, |
| 190 | + Kutu{10, 10, 1, SARI}, |
| 191 | + Kutu{1, 1, 20, SIYAH}, |
| 192 | + Kutu{10, 10, 1, MAVI}, |
| 193 | + Kutu{10, 30, 1, BEYAZ}, |
| 194 | + Kutu{20, 20, 20, SARI}, |
| 195 | + } |
| 196 | + |
| 197 | + fmt.Printf("%d adet kutumuz var\n", len(kutular)) |
| 198 | + fmt.Println("İlk kutunun hacmi ", kutular[0].Hacim(), "cm³") |
| 199 | + fmt.Println("Son kutunun rengi", kutular[len(kutular)-1].renk.String()) |
| 200 | + fmt.Println("En büyük kutu", kutular.EnBuyuklerininRengi().String()) |
| 201 | + |
| 202 | + // Hepsini siyaha boyayalım |
| 203 | + kutular.SiyahaBoya() |
| 204 | + |
| 205 | + fmt.Println("İkinci kutunun rengi", kutular[1].renk.String()) |
| 206 | + fmt.Println("En büyüğü", kutular.EnBuyuklerininRengi().String()) |
| 207 | +} |
| 208 | +``` |
| 209 | + |
| 210 | +Bazı sabitleri ve özelleştirilmiş tür/tipleri tanımlarız |
| 211 | + |
| 212 | +- `Renk`'i `byte` 'ın takma adı olarak kullanın. |
| 213 | +- Hacim, yukseklik, genislik, derinlik ve renk alanlarını içeren `Kutu` struct ını tanımlayın. |
| 214 | +- `Kutu` yu alanı olarak alan `KutuListesi` strruct ı tanımlayın. |
| 215 | + |
| 216 | +Daha sonra özelleştirilmiş türlerimiz/tiplerimiz için bazı methodlar tanımladık. |
| 217 | + |
| 218 | +- `Hacim()` Kutu yu alıcısı olarak kullanır ve onun hacmini döndürür. |
| 219 | +- `RenkAta(r Renk)` Kutu'nun rengini değiştirir. |
| 220 | +- `EnBuyuklerininRengi()` en büyük hacimli Kutu'nun rengini döndürür. |
| 221 | +- `SiyahaBoya()` KutuListesi içindeki tüm Kutu'ların rengini SIYAH yapar. |
| 222 | +- `String()` Renk'i alıcısı olarak kullanır ve Renk adını string olarak döndürür. |
| 223 | + |
| 224 | +Gereksinimlerimizi tanımlamak için kelimeler kullandığımız zaman daha açıklayıcı değil mi? |
| 225 | + |
| 226 | +### İşaretçiyi alıcı olarak kullanmak |
| 227 | + |
| 228 | +RenkAta metoduna bir göz atalım. Alıcısı Kutunun bir işaretçisidir. Evet, `*Kutu`yu alıcı olarak kullanabilirsiniz. Neden burada bir işaretçi kullanıyoruz? Çünkü bu methodda Kutu'nun rengini değiştirmek istiyoruz. Dolayısıyla, bir işaretçi kullanmazsak, bu yalnızca Kutu'nun kopyasındaki değeri değiştirir. |
| 229 | + |
| 230 | +Bir alıcının bir methodun ilk argümanı olduğunu görürsek, nasıl çalıştığını anlamak zor değildir. |
| 231 | + |
| 232 | +Neden RenkAta() methodunda `k.Renk = r` yerine` (*k).Renk = r` kullanmadığımızı soruyor olabilirsiniz. Her iki kullanımda da sorun yok çünkü Go bu görevi nasıl gerçekleştireceğini bilir. Şimdi Go'nun daha büyüleyici olduğunu düşünmüyor musunuz? |
| 233 | + |
| 234 | +Ayrıca `SiyahaBoya` methodunda da neden `(&kl[i]).RenkAta(SIYAH)` kullanıp kullanmamamız gerektiğini de sorabilirsiniz. Çünkü `RenkAta` methoduna bir işaretçi geçmişizdir zaten. Yine iki kullanımda Go için problem değil, ikisinin de nasıl yorumlanacağını bilir! |
| 235 | + |
| 236 | +### method kalıtımı |
| 237 | + |
| 238 | +Son bölümde alanların kalıtımını öğrendik. Benzer şekilde Go'da method kalıtımı da vardır. Eğer anonim bir alanın methodları varsa, alanı içeren struct da ondaki tüm methodlara sahip olacaktır. |
| 239 | +```Go |
| 240 | +package main |
| 241 | + |
| 242 | +import "fmt" |
| 243 | + |
| 244 | +type Insan struct { |
| 245 | + ad string |
| 246 | + yas int |
| 247 | + telefon string |
| 248 | +} |
| 249 | + |
| 250 | +type Ogrenci struct { |
| 251 | + Insan // anonymous field |
| 252 | + okul string |
| 253 | +} |
| 254 | + |
| 255 | +type Calisan struct { |
| 256 | + Insan |
| 257 | + sirket string |
| 258 | +} |
| 259 | + |
| 260 | +// Insan içinde bir method tanımı |
| 261 | +func (i *Insan) Merhaba() { |
| 262 | + fmt.Printf("Merhaba, Benim adım %s. Bana %s nolu telefondan ulaşabilirsiniz.\n", i.ad, i.telefon) |
| 263 | +} |
| 264 | + |
| 265 | +func main() { |
| 266 | + murat := Calisan{Insan{"Murat", 45, "555 5555555"}, "Golang Inc"} |
| 267 | + adem := Ogrenci{Insan{"Adem", 25, "555 5555556"}, "MIT"} |
| 268 | + |
| 269 | + murat.Merhaba() |
| 270 | + adem.Merhaba() |
| 271 | +} |
| 272 | +``` |
| 273 | +### Method Overriding |
| 274 | + |
| 275 | +Eğer Calisan'ın kendi `Merhaba` methoduna sahip olmasını istiyorsak, Calisan'da aynı adı tasıyan bir method tanımlayabiliriz ve böylece `Merhaba` methodunu çağırdığımızda Insan içinde tanımlı olan method gizlenecektir. |
| 276 | +```Go |
| 277 | +package main |
| 278 | + |
| 279 | +import "fmt" |
| 280 | + |
| 281 | +type Insan struct { |
| 282 | + ad string |
| 283 | + yas int |
| 284 | + telefon string |
| 285 | +} |
| 286 | + |
| 287 | +type Ogrenci struct { |
| 288 | + Insan |
| 289 | + okul string |
| 290 | +} |
| 291 | + |
| 292 | +type Calisan struct { |
| 293 | + Insan |
| 294 | + sirket string |
| 295 | +} |
| 296 | + |
| 297 | +func (i *Insan) Merhaba() { |
| 298 | + fmt.Printf("Merhaba, Benim adım %s. Bana %s nolu telefondan ulaşabilirsiniz.\n", i.ad, i.telefon) |
| 299 | +} |
| 300 | + |
| 301 | +func (c *Calisan) Merhaba() { |
| 302 | + fmt.Printf("Merhaba, Benim adım %s, %s şirketinde çalışıyorum. Bana %s bu numaradan ulaşabilirsiniz.\n", c.ad, |
| 303 | + c.sirket, c.telefon) //Evet burada iki satıra ayırarak yazabilirsiniz. |
| 304 | +} |
| 305 | + |
| 306 | +func main() { |
| 307 | + murat := Calisan{Insan{"Murat", 45, "555 5555555"}, "Golang Inc"} |
| 308 | + adem := Ogrenci{Insan{"Adem", 25, "555 5555556"}, "MIT"} |
| 309 | + |
| 310 | + murat.Merhaba() |
| 311 | + adem.Merhaba() |
| 312 | +} |
| 313 | + |
| 314 | +``` |
| 315 | +Artık Nesne-yönelimli program yazabiliyorsunuz. methodların dışarıya açık olup olmayacağını(public/private) method isminin ilk harfini büyük/küçük yaparak sağlayabilirsiniz. |
| 316 | + |
| 317 | +## Links |
| 318 | + |
| 319 | +- [Rehber](preface.md) |
| 320 | +- Önceki bölüm: [struct](02.4.md) |
| 321 | +- Sonraki bölüm: [interface](02.6.md) |
0 commit comments