Dart'ta Derinlemesine Constructor Kullanımı

Constructors (Yapıcılar); sınıfın adıyla aynı ada sahip, bir nesne oluşturulduğunda başlatmak için kullanılan metotlardır. Bir dönüş tipine sahip olmazlar ve başlangıç değerleri vermek için parametreli ya da parametresiz olarak oluşturulabilirler.

Dart'taki tüm sınıfların kendi varsayılan yapıcıları vardır. Eğer siz yazmış olduğunuz bir sınıf için bir yapıcı oluşturmazsanız, derleyici sizin için üye değişkenlere varsayılan değerleri atayarak bir yapıcı oluşturacaktır.

Aşağıdaki gibi yapıcısı olmayan bir sınıf oluşturalım.

class AnyClass {}

Ardından bu sınıftan bir örnek oluşturarak yazdıralım.

var anyClass = AnyClass();
print("AnyClass: $anyClass");

Çıktısı aşağıdaki gibi oluşacaktır.

flutter: AnyClass: Instance of 'AnyClass'

Örneğimizdeki AnyClass'ına şimdi bir yapıcı ekleyelim.

class AnyClass {
  AnyClass() {
    print("AnyClass Constructor");
  }
}

Direkt olarak sınıfımızı çağırdığımızda

AnyClass();

Çıktısı aşağıdaki gibi oluşacaktır.

flutter: AnyClass Constructor

İkinci örneğimizde AnyClass'ını çağırdığımızda, direkt olarak yapıcısını çalıştırmış oldu ve yapıcısı içerisindeki print işlemi ile "AnyClass Constructor" mesajını yazdırmış oldu.

Buradan çıkartılması gereken sonuç, ilgili sınıf çağırıldığında varsayılan olan bazı işlemleri yapmak istediğinizde, bunu yapıcı üzerinde gerçekleştirebilirsiniz.

Yapıcılar/Constructors'ın Özellikleri

Yapıcı özelliklerini aşağıdaki gibi listeleyebliriz.

  1. Bir nesne oluşturulduğunda, yapıcı otomatik olarak çağrılır.
  2. Yapıcıları tanımlarken belirttiğimiz gibi, yapıcının adı, sınıf adıyla aynı olmalıdır.
  3. Yapıcılar, bir dönüş tipine sahip olamaz.
  4. Eğer sınıf içerisinde bir oluşturucu belirtilmemişse, varsayılan olarak parametresiz yapıcı kullanılır. (Yukarıdaki örneğimizde olduğu gibi.)

Yapıcı Türleri

Üç tür yapıcı bulunur. Bunlar;

  1. Default Constructor (Varsayılan Yapıcı)
  2. Parameterized Constructor (Parametreli Yapıcı)
  3. Named Constructor (Adlandırılmış Yapıcı)

olarak isimlendirilir.

Default constructor:

Yukarıda bahsettiğimiz AnyClass örneği ile varsayılan yapıcı (default constructor) çalışmasını yapmış olduk. Eğer tanım olarak söyleyecek olursak, herhangi bir parametresi olmayan yapıcıya verilen isimdir diyebiliriz.

Parameterized Constructor:

Parametreli yapıcı, parametre alan yapıcıdır.

Daha iyi anlamak için aşağıdaki sınıfı oluşturalım.

class ClassName {
  ClassName(String name) {
    print("Class name: $name");
  }
}

Bu sınıfın yapıcısını aşağıdaki gibi parametreli olarak çağıralım.

void main() {
  ClassName("Test");
}

Çıktısı aşağıdaki gibi olacaktır.

Class name: Test

Named Constructor:

Diğer bir çok dilde, yapıcınızı aşırı yüklemeniz (overload) mümkündür. Ancak Dart buna izin vermez. Dart ile aynı isimde fakat farklı parametrelere sahip yapıcı oluşturamazsınız. Derleyici hata verir. Ancak adlandırılmış yapıcı (named constructor) ile bunu gerçekleştirmeniz mümkündür. Çünkü adlandırılmış yapıcı, her biri kendi adına sahip birden fazla yapıcı oluşturmanıza olanak sağlar.

Aşağıdaki gibi Named adında 3 farklı yapıcı bulunduran bir sınıf hazırlayalım.

class Named {
  Named.constructorName(String name) {
    print("constructorName: $name");
  }

  Named.constructorName2(String name) {
    print("constructorName2: $name");
  }

  Named.constructorName3(String name) {
    print("constructorName3: $name");
  }
}

Bu sınıfın yapıcılarını aşağıdaki gibi çağırabiliriz.

Named.constructorName("Test 1");
Named.constructorName2("Test 2");
Named.constructorName3("Test 3");

Çıktısı ise aşağıdaki gibi olacaktır.

flutter: constructorName: Test 1
flutter: constructorName2: Test 2
flutter: constructorName3: Test 3

Yapıcılar/Constructors'da "this" Anahtar Kelimesinin Kullanımı

"this" anahtar kelimesi, geçerli sınıf nesnesine başvuru yapmak için kullanılır. Sınıf içerisinde bir ad çakışması olmadığı sürece isteğe bağlı olarak kullanılabilir. Ancak aksi durumda bir zorunluluk haline gelecektir.

Bu durumu daha iyi anlamak için aşağıdaki gibi bir sınıf oluşturalım.

class Car {
  late String modelName;
  late int maxSpeed;

  Car(modelName, maxSpeed) {
    modelName =  "Toyota";
    maxSpeed = 200;
    print("Bu arabanın model adı/hız:  $modelName/$maxSpeed.");
  }
}

Şimdi bu sınıfımızı aşağıdaki gibi çağıralım.

Car("Fiat", 160);

Ekran da ne yazmasını bekleriz? Bunun için adım adım irdeleyelim.

Car sınıfını çağırdığımızda ilk olarak yapıcı çağırılacak. modelName/maxSpeed değişkenleri Car sınıfı çağırılırken verildiği gibi Fiat/160 şeklinde gelecek ancak, yapıcının içerisinde bu iki değişkene Toyota/200 ataması yapılacak. print ettiğimizde ekranda aşağıdaki gibi görünecektir.

Bu arabanın model adı/hız:  Toyota/200.

Bunun yanında dikkat ettiyseniz Car sınıfı içerisinde bulunan modelName/maxSpeed isimli sınıf değişkenlerini hiç kullanmamış olduk ve başlangıç değeri de vermedik. Burada late anahtar kelimesini kullanarak Dart'a, bu değişkene daha sonra değer atayacağımızı belirtiyor ve hata vermemesini istiyoruz. Dart bu sebeple hata vermiyor ancak biz yine de bu değişkenleri atıl olarak bırakmış oluyoruz.

O zaman onları oyuna dahil edelim..

Örneğimizi aşağıdaki gibi güncelliyoruz ve tek yaptığımı şu oluyor. Yapıcı içerisindeki modelName/maxSpeed değişkenlerine this anahtar sözcüğünü ekliyoruz.

class Car {
  late String modelName;
  late int maxSpeed;

  Car(modelName, maxSpeed) {
    this.modelName =  "Toyota";
    this.maxSpeed = 200;
    print("Bu arabanın model adı/hız:  $modelName/$maxSpeed.");
  }
}

Şimdi bu sınıfımızı tekrar aşağıdaki gibi çağıralım.

Car("Fiat", 160);

Bu sefer çıktımız aşadağıdaki gibi değişti.

Bu arabanın model adı/hız:  Fiat/160.

Neden?

print("Bu arabanın model adı/hız:  $modelName/$maxSpeed.");

Çıktı aldığımız yukarıdaki satırda, yapıcıya ait modelName/maxSpeed değişkenlerini kullanıyoruz. Ancak this anahtar kelimesini kullanarak Toyata/200 değerlerine sahip modelName/maxSpeed değişkenlerimiz, sınıf değişkenlerini temsil ediyor. Bu değişkenlerini de örneğimizin hiç bir yerinde print etmediğimiz için, ekrana basılan değerler yapıcıya verilen değerler olarak ekrana basılıyor. Yani Fiat/160.

Bunu aşağıdaki debug ekranında çok daha iyi gözlemleyebiliriz.

This Keyword

Ancak bu kullanım şekli en iyi pratiklerden değildir. Örneğin başından beri en doğru kullanım şekli ise aşağıdaki gibi olmalıdır.

class Car {
  String modelName;
  int maxSpeed;

  Car(this.modelName, this.maxSpeed) {
    print("Bu arabanın model adı/hız:  $modelName/$maxSpeed.");
  }
}

Neden?

Sınıf örneği ilk oluşturulduğunda sınıfa ait yapıcı çağırılacak. Yapıcının alacağı parametreler sınıf değişkenlerine işaret edeceği için, yapıcının içerisinde değişkenlere tekrar atama yapma gerekliliğini ortadan kaldıracak, aynı zamanda başlangıçta null olarak oluşan modelName/maxSpeed değişkenlerinin içerisini de dolduracağından late anahtar kelimesi ile tanımlanması zorunluluğunu ortadan kaldıracaktır.

Şimdiye kadarki örneklerimizi de göz önünde bulundurarak, yapıcı içerisinde this anahtar sözcüğü ile ilgili şöyle bir özet geçebiliriz.

this anahtar sözcüğüyle,

1. Geçerli sınıf nesnesini işaret etmek için kullanabilirsiniz.

2. Mevcut sınıf değişkenlerine atıfta bulunmak için kullanabilirsiniz.

3. Mevcut sınıf yapıcısını somutlaştırabilir veya çağırabilirsiniz.

4. Yapıcı çağrısında parametre olarak geçebilirsiniz.

5. Metot çağrısında parametre olarak geçebilirsiniz.

6. Sınıf ve yapıcı arasındaki adlandırma çatışmasını ortadan kaldırabilirisiniz.

7. Geçerli sınıf örneğini döndürmek için kullanılabilirsiniz.

Derinlemesine Detaylar

Dart'da yapıcılar ile ilgili temel bilgilere sahip olmuş olduk. Bu başlık ile birlikte biraz daha ince detaylara göz atacağız.

Varsayılan Değerli Yapıcı Oluşturma

Parameterized Constructor (Parametreli Yapıcı) ve Named Constructor (Adlandırılmış Yapıcı) türlerinde, sınıfın bir örneğini oluştururken parametre kullanarak yapılabildiğini öğrenmiştik.

Peki bunları oluştururken bazı alanları varsayılan (default) olarak belirlemek mümkün mü? Sorumuzun cevabı Evet.

Hadi nasıl yapıldığına bir göz atalım..

Öncelikle aşağıdaki gibi örnek bir sınıf oluşturalım.

class YazilimGelistirici {
  String uzmanlikAlani;
  int tecrube;
  bool aktifKodYaziyorMu;
   
  YazilimGelistirici(this.uzmanlikAlani, this.tecrube, this.aktifKodYaziyorMu);
}
 
void main() {
  YazilimGelistirici("Dart", "1", false);
}

Sınıfımız String tipinde uzmanlikAlani, integer tipinde tecrube ve bool tipinde aktifKodYaziyorMu olmak üzere 3 parametre alan bir yapıcıya sahip.

Sınıf örneğini oluştururken bu 3 parametreyi almak yerine uzmanlikAlani ve tecrube bilgilerini almayı, varsayılan olarak da aktifKodYaziyorMu alanını true değeri ile almak istersek kodumuzu nasıl düzenlememiz gerekir?

Bunun için örneğimizi şu şekilde değiştirebiliriz.

class YazilimGelistirici {
  String uzmanlikAlani;
  int tecrube;
  bool aktifKodYaziyorMu;
   
  YazilimGelistirici(this.uzmanlikAlani, this.tecrube): aktifKodYaziyorMu = true;
}
 
void main() {
  YazilimGelistirici("Dart", 3);
}

Yapıcımızı çağırdığımız satırda, iki noktanın (:) sağ tarafına yerleştirilen tanımlamalar ile bunu gerçekleştirmek mümkündür. Böylece kullanıcıdan bu parametre alınmaz ve varsayılan olarak değer verilebilir.

Eğer birden fazla varsayılan kullanmak isterseniz, virgül (,) ile ayırarak bunları arttırabilirsiniz.

Bu çalışma şeklini Named Constructor (Adlandırılmış Yapıcı) türlerinde de aşağıdaki gibi kullanabilirsiniz.

class YazilimGelistirici {
  String uzmanlikAlani;
  int tecrube;
  bool aktifKodYaziyorMu;
   
  YazilimGelistirici(this.uzmanlikAlani, this.tecrube, this.aktifKodYaziyorMu);
  YazilimGelistirici.ozelYapici(this.uzmanlikAlani, this.tecrube): aktifKodYaziyorMu = true;
}
 
void main() {
  YazilimGelistirici("Dart", 3, false);
  YazilimGelistirici.ozelYapici("Flutter", 5);
}

Mevcut bir sınıfın yeni örneklerini (instances) oluşturmayan yapıcı

Aslında bu başlıkla anlatmaya çalıştığımız yapıcının adı fabrika yapıcı (factory constructor).

Fabrika yapıcı (factory constructor), nesnelerin oluşturulması ve yönetilmesi ile ilgili özellikleri çerçeveleyen Creational Design Patterns (Oluşturucu Tasarım Desenleri) türü içerisinde yer alan Factory Design Pattern tekniğini kullanan bir yapıcıdır.

Bir Fabrika modelinde (Factory pattern), oluşturma mantığını istemciye göstermeden nesneler yaratır ve ortak bir arayüz kullanarak yeni oluşturulan nesnelere başvurur.

Bunu nasıl kullandığımızı çok standart ve küçük, fakat temel bir örnekle başlayalım.

enum MessageType {
  sms,
  email,
  notification
}

abstract class Message {
  factory Message(MessageType messageType) {
    switch (messageType) {
      case MessageType.sms: return Sms();
      case MessageType.email: return Email();
      case MessageType.notification: return Notification();
      default: return Sms();
    }
  }

  void send();
}

class Sms implements Message {
  @override
  void send() {
    print("SMS");
  }
}

class Email implements Message {
  @override
  void send() {
    print("EMAIL");
  }
}

class Notification implements Message {
  @override
  void send() {
    print("NOTIFICATION");
  }
}

Örneğimizde Sms, Email ve Notification sınıflarına, factory metodunu yapıcı olarak uyguladığımız Message sınıfı implemente edilmiştir (uygulanmıştır). OOP yaklaşımında Polimorfizm (Çok Biçimlilik)'in de katkılarıyla, Message sınıfın özellik ve metotlarını, Message sınıfını implemente eden bir sınıfa aktardığımızda, Message sınıfına ait metotları implemente edilmiş sınıf içerisinde de (Sms, Email ve Notification sınıfları) kullanabiliriz.

Sms, Email ve Notification sınıfları, send metodunu override ederek, implemente ettikleri Message sınıfının send metodunu geçersiz kılar. Böylece Message sınıfındaki factory metodu her sınıf için ayrı bir send metodu sağlamış olur. Bunun yanında uygulamanızın çalışma zamanında hangi örneğin döndürüleceğine karar vermenize imkan tanıyor olması, önemli özelliklerinden biridir.

Buna göre örneğimizi aşağıdaki gibi çağırdığımızda,

void main(){
    Message(MessageType.sms).send();
    Message(MessageType.email).send();
    Message(MessageType.notification).send();
}

Çıktısı şu şekilde olacaktır.

SMS
EMAIL
NOTIFICATION

Bu çalışma şeklini adlandırılmış yapıcı (named constructor) ile de kullanabilirsiniz.

Değiştirilemez nesnelere sahip, sabit yapıcılar (Constant Constructors)

Dart, sabit yapıcılar (constant constructor) oluşturmanıza imkan veren bir dildir. Bu yapıcınının özelliği; sınıfınızı oluşturduktan sonra değiştirilmeyecek bir nesneyi temsil ediyor olmasıdır. Bundan dolayı da tüm sınıf alanları final olarak tanımlanması gerekir.

Buna göre aşağıdaki örneğimizi hazırlayalım.

class CarConst {
  static const CarConst carConstObject = CarConst("Fiat", 160);

  final String modelName;
  final int maxSpeed;

  const CarConst(this.modelName, this.maxSpeed);
}

void main(){
    print(CarConst.carConstObject.modelName);
}

Çıktımız aşağıdaki gibi olacaktır.

Fiat

Örneğimizde dikkat ettiyseniz yapıcımızın gövdesi bulunmuyor. Çünkü sabit yapıcılar (constant constructor)'ın bir gövdesi olmaz. Dolayısı ile bu örneği aşağıdaki gibi yazamazdık.

const CarConst(this.modelName, this.maxSpeed) {
  print("Bu arabanın model adı/hız:  $modelName/$maxSpeed.");
}

Başka bir yapıcıya yönlendirme yapan yapıcı. (Redirecting Constructors)

Yeniden yönlendiren yapıcılar (redirecting constructor)'ın tanımı tam da başlığımızda belirttiğimiz gibi. Bu yapıcının tek bir amacı var. O da aynı sınıftaki başka bir yapıcıya yönlendirme yapmak.

Yeniden yönlendiren bir oluşturucunun gövdesi boştur ve yapıcı çağrısı, iki nokta üst üste (:) sonrasında gerçekleştirilir.

Hadi bunu örneklendirelim!

class CarRedirect {
  String modelName;
  int totalKilometers;

  CarRedirect(this.modelName, this.totalKilometers){
    print("Bu arabanın model adı/kilometre:  $modelName/$totalKilometers.");
  }
  
  CarRedirect.newcar(String name) : this(name, 0);
}

void main(){
    CarRedirect.newcar("Fiat");
}

Örneğimizdeki CarRedirect sınıfının redirecting constructor'ı (yeniden yönlendiren yapıcı), yalnızca String tipinde bir parametre alır. Aynı satırda iki nokta üst üste (:) sonrasında asıl yapıcıya yönlendirme yapar ve totalKilometers parametresini varsayılan 0 olarak gönderir. Gelen bu parametreler ile asıl yapıcı işletilecek ve yapıcı gövdesindeki print fonksiyonu ile aşağıdaki çıktı oluşacaktır.

Bu arabanın model adı/kilometre:  Fiat/0.

Super Constructors (Super Yapıcılar)'ın kullanılması

Dart'ta extends anahtar kelimesiyle alt sınıf, üst sınıfın tüm değişkenlerini (variables) ve yöntemlerini (methods) devralabilir. Fakat üst sınıfın yapıcısını devralamaz. Bunu Dart'ta super yapıcıyı çağırarak gerçekleştiriyoruz.

Super yapıcıyı çağırmanın iki yolu bulunuyor. Bunlar;

Implicit super:

Implicit türü super constructor kullanımında, derleyici super anahtar kelimesini kullanmaya gerek duymaksızın, bizim için otomatik veya dolaylı olarak bu işlemi gerçekleştirir. Bir sınıfın yeni bir nesnesi oluşturulduğunda, bu sınıfın yapıcısı çağırılırken, sahip olduğu üst sınıfın varsayılan yapıcısını da dolaylı olarak çağırır.

Burada super anahtar kelimesini kullanmıyoruz. Fakat alt sınıf kurucusu çağrıldığında, varsayılan üst sınıf kurucusu otomatik veya dolaylı olarak çağırılmış oluyor.

Bir üst sınıfı (Hayvan sınıfı) ve bir alt sınıfı (Penguen sınıfı) olan, her iki sınıfın da iki kurucuya sahip olduğu bir örnek hazırlayalım.

Implicitly (Dolaylı) çağırırken parametresiz olarak super yapıcıyı şu şekilde kullanırız:

class Hayvan {
  Hayvan(){
    print("Parent Class Hayvan");
  }
}

class Penguen extends Hayvan {

  Penguen() {
    print("Sub Class Penguen");
  }

  show(){
    print("Sub Class içindeki show metodu");
  }
}

main(){
   var penguenObj = Penguen();
   penguenObj.show();
}

çalıştırdığımızda aşağıdaki gibi bir çıktı oluşacaktır.

Parent Class Hayvan
Sub Class Penguen
Sub Class içindeki show metodu

main metodu içerisinde

var penguenObj = Penguen();

satırı çağırıldığında, Penguen sınıfının yapıcısına gidilir. Alt sınıf (Penguen) için bir nesne oluşturduğumuzda, dolaylı olarak (Implicit) üst sınıfın içindeki yapıcı da çağrılacaktır. Böylece ekrana yazacak ilk cümle,

Parent Class Hayvan

olacaktır. Ardından alt sınıfın yapıcısına geri dönecek ve

Sub Class Penguen

satırını yazacaktır. Böylece yapıcılar ile ilgili işlemler bittikten sonra

penguenObj.show();

satırı çalışacak ve show metodu içerisindeki print fonksiyonu ekrana

Sub Class içindeki show metodu

yazacaktır.

Aynı örneğimizi aşağıdaki gibi parametreli olarak da kullanabiliriz.

class Hayvan {
  Hayvan(){
    print("Parent Class Hayvan");
  }
}

class Penguen extends Hayvan {

  Penguen (String name) {
    print("Sub Class Penguen");
  }

  show(){
    print("Sub Class içindeki show metodu");
  }
}

main(){
   var penguenObj = Penguen("Metin tipinde bir isim");
   penguenObj.show();
}

Bu kullanım şeklinde de çıktı değişmeyecektir.

Implict super yapıcıyı ister parametreli ister parametresiz kullanın, üst sınıfın yapıcısı mutlaka varsayılan yapıcı olmalıdır.

Explicit super:

Implict super yapıcı örneğimiziden farklı olarak üst sınıfın yapıcısı eğer varsayılan değilse, yani parametre alıyorsa, alt sınıfın yapıcısında super anahtar kelimesi kullanarak çağırılır.

Buna göre Explicit super yapıcıyı çağırırken şu şekilde kullanırız:

class Hayvan {
   Hayvan(String prmt){
      print("Parent Class Hayvan");
      print("Parent Class parametre: $prmt");
   }
}

class Penguen extends Hayvan {
   
  Penguen() : super("Super Parametre") {
    print("Sub Class Penguen");
  }

  show(){
    print("Sub Class içindeki show metodu");
  }
}

main(){
   var penguenObj = Penguen();
   penguenObj.show();
}

Alt sınıfın kurucusunda açık açık super metodu ile üst sınıfın yapıcısını parametre göndererek çağırırız. Böylece şöyle bir çıktı oluşur.

Parent Class Hayvan
Parent Class parametre: Super Parametre
Sub Class Penguen
Sub Class içindeki show metodu

main metodu içerisinde

var penguenObj = Penguen();

satırı çağırıldığında, Penguen sınıfının yapıcısına gidilir. Biz burada super metodunu açık açık parametresi ile birlikte yazarak, Hayvan sınıfının (miras alınan üst sınıf) yapıcısının işletilmesini isteriz. Böylece ekrana yazacak ilk cümle,

Parent Class Hayvan
Parent Class parametre: Super Parametre

olacaktır. Ardından alt sınıfın yapıcısına geri dönecek ve

Sub Class Penguen

satırını yazacaktır. Böylece yapıcılar ile ilgili işlemler bittikten sonra

penguenObj.show();

satırı çalışacak ve show metodu içerisindeki print fonksiyonu ekrana

Sub Class içindeki show metodu

yazacaktır.

Not.1: İki kullanım şeklinde de parametresiz kullanımda super anahtar kelimesini kullanabilirsiniz. Ancak Implict super kullanım şeklinde super anahtar kelimesini yazmadan da aynı işlemi gerçekleştirebilirsiniz. Yani parametresiz işlemde alt sınıfın yapıcısında Penguen() : super() ile Penguen() yazımı arasında fark yoktur.

Not.2: Bu işlemleri Named Constructors (Adlandırılmış Yapıcılar) ile de gerçekleştirebilirsiniz.

Private Named Constructors (Özel Adlandırılmış Yapıcılar)'ı kullanmak

Bu yapıcıyı, özellikle statik değişkenler (static variables) veya yöntemler (static methods) oluşturmanız gerektiğinde kullanmalısınız.

Statik değişkenler (static variables) ve yöntemler (static methods), bulunduğu sınıflara ait olan varlıklardır. Bu sebeple bu varlıkları sadece bir sınıf örneği oluşturduğunuzda kullanabilirsiniz. Özel adlandırılmış yapıcıları ise bu sınıf örneğinin oluşturulmasına izin vermediğinden dolayı, statik değişkenler (static variables) ve yöntemlere direkt olarak erişim sağlamalısınız.

Dart dilinde diğer bir çok dilde görmeye alışkın olduğumuz private anahtar kelimesi bulunmaz. Bunun yerine alt çizgi (_) ile adlandırılmış yapıcı kullanılarak özel ile bir yapıcı elde edilebilir.

class AppConsts {
  AppConsts._();
}

void main() {
  var appConsts = AppConsts();

}

Yukarıdaki örneğimizde olduğu gibi bir sınıfın nesnesini oluşturuyorsanız,

Couldn't find constructor 'AppConsts'

şeklinde bir derleme hata alırsınız. Çünkü bu yapıcının en önemli vazifesi sınıfın örneğinin oluşturulmasına izin vermemesidir. Tam da bu sebepten dolayı başta da belirttiğimiz gibi özellikle statik değişkenler (static variables) veya yöntemler (static methods) için kullanılması gerekir ve yine bu sebeple, özel adlandırılmış yapıcılar, Singleton kalıbı (pattern) oluşturmak için oldukça kullanışlıdır.

Örneğimizi biraz daha geliştirelim.

class AppConsts {
  AppConsts._();

  static const String testEndpoint = "http://www.google.com/1";
  static const String devEndpoint = "http://www.google.com/2";
  
  static String exportSuffix(String name){
    return "$name.dev";
  }
}

main() {
  print(AppConsts.testEndpoint);
  print(AppConsts.devEndpoint);
  print(AppConsts.exportSuffix("appconst"));
}

Görüldüğü üzere AppConsts sınıfından yeni bir örnek üretmedik. Ancak içeride static olarak tanımladığımız metot ve değişkenlere dışarıdan sorunsuz bir şekilde ulaştık. Buna göre çıktımız da aşağıdaki gibi oluştu.

http://www.google.com/1
http://www.google.com/2
appconst.dev

Bu kullanım şeklinin dışında aşağıdaki örnekte olduğu gibi, belli sınıfların örneğinin oluşmasını istemiyorsanız, super constructor ile de kullanabilirsiniz.

class Calisan {
  Calisan._() {
    print("Bu işi yapalım.");
  }
}

class Patron extends Calisan {
  Patron() : super._();
}

void main() {
  var patron = Patron();
}

Egemen MEDE - 19.09.2022