it-swarm.asia

Yapıcı genellikle yöntem çağırmamalıdır

Bir meslektaşıma bir metodu çağıran bir kurucunun neden bir antipattern olabileceğini anlattım.

örnek (paslı C++'ımda)

class C {
public :
    C(int foo);
    void setFoo(int foo);
private:
    int foo;
}

C::C(int foo) {
    setFoo(foo);
}

void C::setFoo(int foo) {
    this->foo = foo
}

Ek katkınızla bu gerçeği daha iyi motive etmek istiyorum. Örnekleriniz, kitap referanslarınız, blog sayfalarınız veya ilkelerin adlarınız varsa, bunlar çok hoş karşılanır.

Edit: Ben genel olarak konuşuyorum, ama biz python kodlama.

12
Stefano Borini

Bir dil belirtmediniz.

C++ 'da bir yapıcı sanal bir işlevi çağırırken dikkat etmelidir, çağıran asıl işlev sınıf uygulamasıdır. Uygulama olmadan saf bir sanal yöntemse, bu bir erişim ihlali olacaktır.

Bir kurucu sanal olmayan fonksiyonları çağırabilir.

Diliniz Java burada işlevler varsayılan olarak sanaldır) çok dikkatli olmanız mantıklıdır.

C # durumu beklediğiniz gibi ele alıyor gibi görünüyor: yapıcılarda sanal yöntemleri çağırabilirsiniz ve en son sürümü çağırır. Yani C # 'da bir anti-desen değil.

Yöntemleri kuruculardan çağırmanın yaygın bir nedeni, ortak bir "init" yöntemi çağırmak isteyen birden çok kurucunuzun olmasıdır.

Yıkıcıların sanal yöntemlerle aynı sorunu yaşayacağına dikkat edin, böylece yıkıcınızın dışında duran ve temel sınıf yıkıcısı tarafından çağrılmasını bekleyecek sanal bir "temizleme" yöntemine sahip olamazsınız.

Java ve C # 'nin yıkıcıları yoktur, kesinleştiricileri vardır. Java ile olan davranışı bilmiyorum.

Bu konuda C # temizliğini doğru işlemektedir.

(Java ve C # öğelerinin çöp toplama özelliğine sahip olmasına rağmen, yalnızca bellek ayırmayı yönetir. Yıkıcısının yapması gereken başka bir temizleme işlemi vardır, bu da belleği serbest bırakmaz).

26
CashCow

Tamam, şimdi sınıf yöntemleri vs örnek yöntemleri ile ilgili karışıklık giderildi, bir cevap verebilirim :-)

Sorun genel olarak bir kurucudan çağrı örneği yöntemlerinde değildir; sanal yöntemleri (doğrudan veya dolaylı olarak) çağırarak. Ve ana nedeni yapıcı içinde iken, nesne henüz tam olarak inşa edilmemiştir . Ve özellikle alt sınıf parçaları, taban sınıfı yapıcısı yürütülürken hiç oluşturulmamıştır. Bu yüzden iç durumu dile bağlı bir şekilde tutarsızdır ve bu farklı dillerde farklı ince hatalara neden olabilir.

C++ ve C # zaten başkaları tarafından tartışılmıştır. Java'da en türetilen türün sanal yöntemi çağrılır, ancak bu tür henüz başlatılmaz. Dolayısıyla, bu yöntem türetilmiş türden herhangi bir alan kullanıyorsa, bu alanlar henüz o tarihte doğru şekilde başlatılamayabilir. Bu sorun Effecive Java 2nd Edition , Madde 17: Tasarım ve belge miras için tasarlandı veya başka bir şekilde yasaklandı.

Bunun nesne referanslarını erken yayınlama ile ilgili genel bir sorun olduğunu unutmayın. Örnek yöntemleri örtük bir this parametresine sahiptir, ancak this parametresini açıkça bir yönteme geçirmek benzer sorunlara neden olabilir. Özellikle, nesne başvurusunun başka bir iş parçacığına erken yayınlanması durumunda, bu iş parçacığı, ilk iş parçacığındaki yapıcı bitmeden önce üzerinde zaten yöntemler çağırabilir.

18
Péter Török

Burada yöntem çağrıları kendi içinde bir antipattern olarak düşünmezdim, daha fazla bir kod kokusu. Bir sınıf reset yöntemi sağlıyorsa, bu nesneyi orijinal durumuna döndürür, ardından yapıcıda reset() çağrısı DRY olur. (Sıfırlama yöntemleri hakkında herhangi bir açıklama yapmıyorum).

Yetki için itirazınızı yerine getirmenize yardımcı olabilecek bir makale: http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/

Bu gerçekten çağrı yöntemleri değil, çok fazla şey yapan inşaatçılar hakkında. IMHO, bir kurucudaki yöntemleri çağırmak, bir kurucunun çok ağır olduğunu gösterebilecek bir kokudur.

Bu, kodunuzu test etmenin ne kadar kolay olduğu ile ilgilidir. Nedenleri şunları içerir:

  1. Birim testi çok sayıda yaratım ve yıkımı içerir - bu nedenle inşaat hızlı olmalıdır.

  2. Bu yöntemlerin ne yaptığına bağlı olarak, yapıcıda ayarlanmış bazı (potansiyel olarak denenemez) ön koşullara dayanmadan ayrı kod birimlerinin test edilmesini zorlaştırabilir (örn. Bir ağdan bilgi alın).

7
Paul Butcher

Felsefi olarak kurucunun amacı, ham bir bellek yığınını bir örneğe dönüştürmektir. Yapıcı yürütülürken, nesne henüz mevcut değildir, bu nedenle yöntemlerini çağırmak kötü bir fikirdir. Ne de olsa dahili olarak ne yaptıklarını bilmiyor olabilirsiniz ve nesneyi, çağrıldıklarında en azından varlığını (duh!) Haklı olarak düşünebilirler.

Teknik olarak, bu konuda yanlış bir şey olmayabilir, C++ ve özellikle Python'da dikkatli olmak size kalmış.

Pratik olarak, çağrıları yalnızca sınıf üyelerini başlatan yöntemlerle sınırlamalısınız.

3
user17621

Genel amaçlı bir konu değil. C++ 'da, özellikle miras ve sanal yöntemler kullanılırken bir sorun var, çünkü nesne yapısı geriye doğru gerçekleşiyor ve vtable işaretçileri her kurucu ile sıfırlanıyor miras hiyerarşisinde bir katman oluşturduğundan, sanal bir yöntem çağırıyorsanız, aslında oluşturmaya çalıştığınız sınıfa karşılık gelen ve sanal yöntemleri kullanmanın tüm amacını bozan bir yöntem elde edemeyebilirsiniz.

Sana OOP desteği, vtable işaretçisini başlangıçtan itibaren doğru ayarlayan dillerde, bu sorun yoktur.

2
Mason Wheeler

Bir yöntemi çağırmakla ilgili iki sorun vardır:

  • beklenmedik bir şey (C++) yapabilen veya henüz başlatılmamış nesnelerin parçalarını kullanabilen sanal bir yöntem çağırmak
  • nesne henüz tam olarak tamamlanmadığından (ve dolayısıyla değişmezi tutamayabileceğinden) genel bir yöntemi çağırmak (sınıf değişmezlerini zorlaması gerekir)

Önceki iki durumda düşmediği sürece yardımcı fonksiyon çağırma konusunda yanlış bir şey yoktur.

2
Matthieu M.

Bunu satın almıyorum. Nesne yönelimli bir sistemde, bir yöntemi çağırmak yapabileceğiniz tek şeydir. Aslında bu aşağı yukarı "nesne yönelimli" nin tanım değeri. Eğer bir kurucu herhangi bir yöntem çağıramazsa, o zaman can ne işe yarar?

1
Jörg W Mittag

O.O.P. teori, önemli değil, ama pratikte, her O.O.P. programlama dili yapıcıları farklı işler . Statik yöntemleri çok sık kullanmıyorum.

C++ & Delphi, bazı özellikleri ("alan üyeleri") için başlangıç ​​değerleri vermek zorunda kaldıysanız ve kod çok genişletilmiş, ben yapıcıların uzantısı olarak bazı ikincil yöntemleri ekleyin.

Ve daha karmaşık şeyler yapan başka yöntemler de demeyin.

"Getters" ve "setters" özelliklerine gelince, genellikle durumlarını saklamak için özel/korumalı değişkenleri ve "getters" & "setters" yöntemlerini kullanırım.

Yapıcıda, özellikler durumu alanlarına "varsayılan" değerler atarım, [~ # ~] [~ # ~] "erişimcileri" çağırmadan.

0
umlcat