Soyut bir sınıftaki tüm genel yöntemler sanal olarak işaretlenmeli mi?


12

Son zamanlarda kullandığım bazı OSS üzerinde soyut bir temel sınıf güncellemek zorunda kaldım, böylece onları sanal hale getirerek daha test edilebilir hale geldim (iki kombinasyonu birleştirirken arayüz kullanamadım). Bu, sanal olarak ihtiyaç duyduğum tüm yöntemleri işaretlemem gerekip gerekmediğini veya her genel yöntemi / özelliği sanal olarak işaretlemem gerekip gerekmediğini düşünmemi sağladı. Ben genellikle her yöntem sanal yapılması gerektiğini Roy Osherove katılıyorum ama beni bu gerekli olup olmadığı hakkında düşünme var bu makale geldi . Bunu basitlik için soyut sınıflarla sınırlayacağım, ancak (tüm somut kamu yöntemlerinin sanal olması gerekip gerekmediği tartışmalıdır).

Bir alt sınıfın bir yöntemi kullanmasına izin vermek isteyebileceğinizi, ancak uygulamayı geçersiz kılmasını istemediğinizi görebiliyordum. Ancak, Liskov'un Değiştirme İlkesinin uygulanacağına güvendiğiniz sürece , neden geçersiz kılınmasına izin vermeyesiniz? Soyut olarak işaretleyerek, yine de belirli bir geçersiz kılmaya zorlarsınız, bu yüzden bana göre, soyut bir sınıf içindeki tüm genel yöntemler gerçekten sanal olarak işaretlenmelidir.

Ancak, düşünemeyeceğim bir şey olması durumunda sormak istedim. Soyut bir sınıf içindeki tüm kamu yöntemleri sanallaştırılmalı mıdır?



1
Belki de C # 'da varsayılanın neden sanal olmadığını ancak Java'da olduğunu görmelisiniz. Bunun cevabı size muhtemelen bir fikir verecektir.
Daniel Little

Yanıtlar:


9

Ancak, Liskov'un Değiştirme İlkesinin uygulanacağına güvendiğiniz sürece, neden geçersiz kılınmasına izin vermeyesiniz?

Örneğin, bir algoritmanın iskelet uygulamasının düzeltilmesini ve yalnızca belirli parçaların alt sınıflar tarafından (yeniden) tanımlanmasını istiyorum. Bu, Şablon Yöntemi kalıbı olarak bilinir (aşağıda benim tarafımdan vurgu):

Şablon yöntemi böylece görev semantiğinin daha büyük resmini ve seçim ve yöntem sırasının daha rafine uygulama ayrıntılarını yönetir. Bu daha büyük resim, mevcut görev için soyut ve soyut olmayan yöntemleri çağırır. Soyut olmayan yöntemler tamamen şablon yöntemi tarafından kontrol edilir, ancak alt sınıflarda uygulanan soyut yöntemler, desenin ifade gücünü ve serbestlik derecesini sağlar. Soyut yöntemlerin bir kısmı veya tamamı, bir alt sınıfta uzmanlaşarak alt sınıfın yazarının daha büyük anlambilimde minimum değişikliklerle belirli davranışlar sağlamasına izin verebilir. Şablon yöntemi (soyut olmayan), bu modelde değişmeden kalır ve alt soyut olmayan yöntemlerin ve soyut yöntemlerin başlangıçta amaçlanan sırada çağrılmasını sağlar.

Güncelleme

Üzerinde çalıştığım projelerin somut örnekleri:

  1. çeşitli "ekranlar" aracılığıyla eski bir ana bilgisayar sistemiyle iletişim kurmak. Her ekran, belirli veri bitleri içeren sabit ad, konum ve uzunlukta bir grup alana sahiptir. Bir istek, belirli alanları belirli verilerle doldurur. Yanıt, bir veya daha fazla alandaki verileri döndürür. Her işlem aynı temel mantığı takip eder, ancak ayrıntılar her ekranda farklıdır. Şablon işleme mantığını, ekran işleme mantığının sabit iskeletini uygulamak için uygularken, alt sınıfların ekrana özgü ayrıntıları tanımlamasına izin verdik.
  2. DB tablolarındaki yapılandırma verilerini Excel dosyalarına / dosyalarından verme / alma. Yine, bir Excel dosyasını işlemenin ve DB kayıtlarını eklemenin / güncellemenin veya kayıtları Excel'e boşaltmanın temel şeması her tablo için aynıdır, ancak her tablonun ayrıntıları farklıdır. Şablon Şablonu, kod kopyalarını ortadan kaldırmak ve kodun anlaşılmasını ve bakımını kolaylaştırmak için çok açık bir seçimdir.
  3. PDF belgeleri oluşturma. Her belge aynı yapıya sahiptir, ancak içeriği birçok faktöre bağlı olarak her seferinde farklıdır. Şablon Yöntemi yine, üretim algoritmasının sabit iskeletini duruma özgü, değiştirilebilir ayrıntılardan ayırmayı kolaylaştırır. Aslında. belgenin her biri sıfır veya daha fazla alandan oluşan birkaç bölümden oluştuğu için burada birden çok düzeyde de geçerlidir . Şablon Yöntemi burada 3 farklı seviyede uygulanmaktadır.

İlk iki durumda, orijinal eski uygulama Strateji'yi kullandı ve elbette yıllar boyunca burada ve orada küçük farklılıklar kazandıran çok sayıda çoğaltılmış kodla sonuçlandı, çok sayıda çoğaltılmış veya biraz farklı hatalar içeriyordu ve bakımı çok zordu. Şablon Yöntemi'ne (ve Java ek açıklamalarını kullanmak gibi diğer bazı geliştirmelere) yeniden odaklanmak, kod boyutunu yaklaşık% 40-70 oranında azalttı.

Bunlar sadece aklıma gelen en son örnekler. Şimdiye kadar üzerinde çalıştığım hemen hemen her projeden daha fazla örnek verebilirim.


Basitçe GoF'den alıntı yapmak bir cevap değildir. Böyle bir şey yapmak için gerçek bir sebep vermeniz gerekir.
DeadMG

@DeadMG, kariyerim boyunca Şablon Yöntemi'ni düzenli olarak kullanıyorum, bu yüzden çok pratik ve kullanışlı bir desen olduğu açıktı (GoF modellerinin çoğu ... bunlar teorik akademik egzersizler değil, toplandı gerçek dünya deneyiminden). Ama görünüşe göre herkes onunla aynı fikirde değil ... bu yüzden cevabım için birkaç somut örnek ekliyorum.
Péter Török

2

Soyut bir temel sınıfta sanal olmayan yöntemlere sahip olmak son derece makul ve bazen arzu edilir; sadece soyut bir sınıf olması, her parçasının polimorfik olarak kullanılabilir olması gerektiği anlamına gelmez.

Örneğin, sanal işlev çağrılmadan önce belirli ön koşulların veya son koşulların karşılandığından emin olmak için bir işlevin sanal olmayan üye işlevinden polimorfik olarak çağrıldığı 'Sanal olmayan polimorfizm' deyimini kullanmak isteyebilirsiniz.

class MyAbstractBaseClass
{
protected:
    virtual void OverrideMe() = 0;
public:
    void CallMeFirst();

    void CallMe()
    {
        CallMeFirst();
        OverrideMe();
    }
};

Genel davranış aynı kaldığı sürece, bunun sanal hale getirilebileceğini iddia ediyorum. Öncesi / sonrası koşullarını farklı bir uygulama (veritabanı veya bellek içi) kullanarak doldurabilirsiniz. Aksi takdirde, özel bir işlev olmalı?
Justin Pihony

2

Sınıfın soyut olması için bir sınıfın ONE sanal yöntemi içermesi yeterlidir. Kullanmayı planladığınız polimorfizmin türüne göre, hangi yöntemleri sanal olarak istediğiniz ve hangilerini istemediğinize dikkat etmek isteyebilirsiniz.


1

Soyut bir sınıfta sanal olmayan bir yöntem kullanımının ne olduğunu kendinize sorun. Böyle bir yöntemin faydalı olması için bir uygulaması olmalıdır. Ancak sınıfın bir uygulaması varsa, buna yine de soyut bir sınıf denebilir mi? Dil / derleyici buna izin verse bile mantıklı geliyor mu? Şahsen ben öyle düşünmüyorum. Torunların uygulaması beklenen soyut yöntemlerle normal bir sınıfınız olurdu.

Birincil dilim C # değil Delphi. Delphi'de, bir yöntem özetini işaretlerseniz, bunu da sanal olarak işaretlemeniz gerekir veya derleyici şikayet eder. En son dil değişikliklerini çok yakından takip etmedim, ancak soyut sınıflar Delphi'de ise veya Delphi'ye gelirse, derleyicinin sanal olmayan herhangi bir yöntem, herhangi bir özel yöntem ve soyut işaretli bir sınıf için herhangi bir yöntem uygulaması hakkında şikayet etmesini beklerdim. sınıf düzeyinde.


2
Bazı soyut yöntemlere, bazı sanal yöntemlere ve bazı sanal olmayan yöntemlere sahip soyut bir sınıfın olması mantıklı geliyor. Ben her zaman tam olarak ne yapmak istediğine bağlı olduğunu düşünüyorum.
svick

3
İlk önce C # q'larınızın üzerinden geçeceğim. C # 'da soyut bir yöntem dolaylı olarak sanaldır ve bir uygulaması olamaz. İlk noktanıza gelince, C # 'daki soyut bir sınıf bir çeşit uygulamaya sahip olabilir ve olmalıdır (aksi takdirde sadece bir arayüz kullanmalısınız). Bir sınıfın soyut olduğu nokta, sınıfının ZORUNLU olması gerektiğidir, ancak (teorik olarak) tüm alt sınıfların kullanacağı mantığı içerir. Bu, kod çoğaltmasını azaltır. Sorduğum şey, bu uygulamalardan herhangi birinin geçersiz kılınmaktan (aslında temel yolun tek yol olduğunu söylemek) kapatılması gerekip gerekmediğidir.
Justin Pihony

@ JustinPihony: teşekkürler. Delphi'de, bir yöntem özetini işaretlediğinizde, derleyici bunun için bir uygulama sağlarsanız şikayet edecektir. Farklı dillerin kavramları farklı şekilde nasıl uyguladığı ve böylece kullanıcılarında farklı beklentiler yarattığı ilginçtir.
Marjan Venema

@svick: evet mükemmel bir anlam ifade ediyor, ben buna soyut bir sınıf demezdim, ama soyut yöntemlere sahip bir sınıf ... Ama sanırım bu benim yorumum olabilir.
Marjan Venema

@MarjanVenema, ama bu C # terminolojisi değil kullanır. Bir sınıfta herhangi bir yöntemi abstractişaretlerseniz, tüm sınıfı da işaretlemelisiniz abstract.
svick

0

Ancak, Liskov'un Değiştirme İlkesinin uygulanacağına güvendiğiniz sürece, neden> geçersiz kılınmasına izin vermeyesiniz?

Belirli yöntemleri sanal yapmazsınız çünkü bunun böyle olduğuna inanmıyorsunuz. Ayrıca, sanal olmayan bazı yöntemleri yaparak, mirasçılara hangi yöntemlerin uygulanması gerektiğini bildiriyorsunuz.

Kişisel olarak, sınıf kullanıcılarının tutarlı varsayılanlara sahip olabilmesi ve uygulayıcıların bu zımni davranışı bozma hatasını bile yapamaması için genellikle sanal olmayan kolaylık sağlamak için mevcut yöntem aşırı yüklemeleri yapacağım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.