Uzun yöntem yeniden düzenleme: olduğu gibi bırakma ve yöntemlere ayırma ve yerel işlevleri kullanma


9

Bunun gibi uzun bir yöntemim olduğunu varsayalım:

public void SomeLongMethod()
{
    // Some task #1
    ...

    // Some task #2
    ...
}

Bu yöntemde, ayrı bir yönteme veya yerel işleve taşınması gereken tekrarlayan parçalar yoktur.

Uzun metotların kod kokusu olduğunu düşünen birçok kişi (ben dahil) var. Ayrıca burada kullanım fikrini sevmiyorum #regionve bunun neden kötü olduğunu açıklayan çok popüler bir cevap var .


Ama bu kodu yöntemlere ayırırsam

public void SomeLongMethod()
{
    Task1();

    Task2();
}

private void Task1()
{
    // Some task #1
    ...
}

private void Task2()
{
    // Some task #1
    ...
}

Aşağıdaki sorunları görüyorum:

  • Sınıf tanım kapsamını, tek bir yöntemle dahili olarak kullanılan Task1ve Task2yalnızca iç kısımları SomeLongMethod(veya kodumu okuyan her insanın bu fikri çıkarmak zorunda kalacağı) belgelemem gerektiği anlamına gelen tanımlarla kirletme .

  • Tek bir SomeLongMethodyöntemde yalnızca bir kez kullanılacak yöntemlerin IDE otomatik tamamlama (örn. Intellisense) .


Bu yöntem kodunu yerel işlevlere ayırırsam

public void SomeLongMethod()
{
    Task1();

    Task2();

    void Task1()
    {
        // Some task #1
        ...
    }

    void Task2()
    {
        // Some task #1
        ...
    }
}

bunun ayrı yöntemlerin dezavantajları yoktur, ancak bu orijinal yöntemden daha iyi görünmemektedir (en azından benim için).


Hangi sürümü SomeLongMethodsizin için daha sürdürülebilir ve okunabilir ve neden?



@gnat sorum java için değil c # için özeldir . Ana endişem, klasik yöntemle yerel işleve ilişkin, sadece yöntemlere ayrı değil, değil.
Vadim Ovchinnikov

@gnat Ayrıca AFAIK Java (C # 'dan farklı olarak) iç içe işlevleri desteklemez.
Vadim Ovchinnikov

1
özel anahtar kelime mutlaka 'sınıf tanımı kapsamınızı' korur?
Ewan

1
bekle ...... sınıfın ne kadar büyük?
Ewan

Yanıtlar:


13

Bağımsız görevler, bağımsız yöntemlere taşınmalıdır. Bu hedefi geçersiz kılacak kadar büyük bir dezavantaj yoktur.

Sınıfın ad alanını kirlettiğini söylüyorsunuz, ancak bu, kodunuzu çarpanlarına ayırırken bakmanız gereken ödünleşim değildir. Sınıfın gelecekteki bir okuyucusunun (örneğin siz) " Bu özel yöntem ne yapıyor ve değiştirilen gereksinimlerin söylediklerini yapması için nasıl değiştirmeliyim?" " Sınıftaki tüm yöntemlerin amacı ve duygusu ne?" den daha fazladır. Bu nedenle, yöntemlerin her birini daha kolay anlaşılır kılmak (daha az unsura sahip olmak) tüm sınıfı anlamayı kolaylaştırmaktan çok daha önemlidir. (daha az yöntemi kullanarak).

Tabii ki, görevler gerçekten bağımsız değilse, ancak hareket etmek için bazı durum değişkenleri gerektiriyorsa, bunun yerine bir yöntem nesnesi, yardımcı nesne veya benzer bir yapı doğru seçim olabilir. Ve eğer görevler tamamen kendi kendine yetiyorsa ve uygulama alanıyla hiç bağlantılı değilse (örneğin sadece dize biçimlendirmesi varsa, akla gelebilecek şekilde tamamen farklı (faydalı) bir sınıfa girmelidirler. "sınıf başına düşen yöntemleri tutmak" en iyi ihtimalle yardımcı bir hedeftir.


Yani yerel fonksiyonlar için değil, metodlar içindesiniz, değil mi?
Vadim Ovchinnikov

2
@VadimOvchinnikov Modern bir kod katlama IDE'si ile çok az fark var. Yerel bir işlevin en büyük avantajı, aksi takdirde parametre olarak iletmeniz gereken değişkenlere erişebilmesidir, ancak bunlardan çok varsa, görevler gerçekten başlamak için bağımsız değildi.
Kilian Foth

6

Her iki yaklaşımı da sevmiyorum. Daha geniş bir bağlam sağlamadınız, ancak çoğu zaman şöyle görünür:

Birden fazla hizmetin gücünü tek bir sonuçta birleştirerek iş yapan bir sınıfınız var.

class SomeClass
{
    private readonly Service1 _service1;
    private readonly Service2 _service2;

    public void SomeLongMethod()
    {
        _service1.Task1();
        _service2.Task2();       
    }
}

Hizmetlerinizin her biri mantığın yalnızca bir bölümünü uygular. Sadece bu servisin yapabileceği özel bir şey. Yalnızca ana API'yi destekleyen yöntemlerden başka özel yöntemleri varsa, bunları kolayca sıralayabilirsiniz ve yine de çok fazla olmamalıdır.

class Service1
{
    public void Task1()
    {
        // Some task #1
        ...
    }

    private void SomeHelperMethod() {}
}

class Service2
{
    void Task2()
    {
        // Some task #1
        ...
    }
}

Sonuç olarak: yöntemleri gorup etmek için kodunuzda bölgeler oluşturmaya başlarsanız, mantıklarını yeni bir hizmetle sarmalamayı düşünmenin zamanı gelmiştir.


2

Yöntem içinde işlevler yaratmadaki sorun, yöntemin uzunluğunu azaltmamasıdır.

'Korumaya özel' ekstra koruma düzeyi istiyorsanız, yeni bir sınıf oluşturabilirsiniz

public class BigClass
{
    public void SomeLongMethod();

    private class SomeLongMethodRunner
    {
        private void Task1();
        private void Task2();
    }
}

Ancak sınıflardaki sınıflar çok çirkin: /


2

Değişkenler ve yöntemler gibi dil yapılarının kapsamını en aza indirmek iyi bir uygulamadır. Örneğin global değişkenlerden kaçının .. Kodun anlaşılmasını kolaylaştırır ve yapıya daha az yerde erişilebildiğinden kötüye kullanımın önlenmesine yardımcı olur.

Bu, yerel işlevleri kullanmaktan bahsediyor.


1
hmm kesinlikle kodu yeniden kullanmak == birçok arayanlar arasında bir yöntemi paylaşmak. yani kapsamını en üst düzeye çıkarmak
Ewan

1

Uzun yöntemlerin genellikle bir kod kokusu olduğunu kabul ediyorum, ancak tüm resmin bu olduğunu düşünmüyorum, bunun yerine bir soruna işaret eden yöntem uzun. Genel kuralım, kodun birden fazla farklı görevi yerine getirmesi durumunda bu görevlerin her birinin kendi yöntemi olması gerekir. Benim için bu kod bölümlerinin tekrarlayan olup olmadığı önemli değil; gelecekte hiç kimsenin bunları ayrı ayrı çağırmak istemeyeceğinden kesinlikle emin değilseniz (ve emin olmak çok zor bir şeydir!) sınıf dışında kullanılmasını beklemezsiniz).

İtiraf etmeliyim ki henüz yerel işlevleri kullanmadım, bu yüzden anlayışım burada tam olmaktan çok uzak, ancak sağladığınız bağlantı, genellikle bir lambda ifadesine benzer şekilde kullanılacağını gösteriyor (burada bir dizi kullanım örneği olmasına rağmen) lambdalardan daha uygun olabilecekleri veya lambda kullanamayacağınız yerlerde bkz . lambda ifadelerine kıyasla yerel işlevler . Özellikler ). O zaman burada, 'diğer' görevlerin ayrıntı düzeyine inebileceğini düşünüyorum; onlar oldukça önemsiz ise, belki de yerel bir işlev iyi olurdu? Öte yandan, kodu başka bir yöntemden çağrılmış olandan çok daha az anlaşılabilir ve sürdürülebilir hale getiren behemoth lambda ifadelerinin (muhtemelen bir geliştiricinin LINQ'u keşfettiği yerlerde) örnekler gördüm.

Yerel Fonksiyonlar sayfa belirtiyor:

Yerel işlevler kodunuzun amacını netleştirir. Kodunuzu okuyan herkes, içeren yöntem dışında yöntemin çağrılabilir olmadığını görebilir. Ekip projeleri için, başka bir geliştiricinin yöntemi doğrudan sınıfta veya davranışta başka bir yerden yanlışlıkla çağırmasını imkansız hale getirir. '

Kullanım nedeni olarak bu konuda gerçekten MS ile olduğumdan emin değilim. Yöntemin kapsamı (adı ve yorumlarıyla birlikte) o zaman niyetinizin ne olduğunu netleştirmelidir . Yerel bir İşlev ile, diğer geliştiricilerin bunu daha sakrosanct olarak görebilir, ancak potansiyel olarak gelecekte bu işlevin yeniden kullanılmasını gerektiren bir değişiklik olursa kendi prosedürlerini yazıp Yerel İşlevi yerinde bıraktığı noktaya gelebilir. ; böylece kod çoğaltma sorunu yaratılır. Yukarıdaki alıntıdan sonraki ikinci cümle, ekip üyelerini aramadan önce özel bir yöntemi anlamalarına güvenmiyorsanız ve bu yüzden uygun olmayan bir şekilde çağırırsanız (eğitim burada daha iyi bir seçenek olsa da, kararınız bundan etkilenebilir) ilgili olabilir. .

Özetle, genel olarak, yöntemlere ayrılmayı tercih ederim, ancak MS bir nedenden dolayı Yerel İşlevler yazdı, bu yüzden kesinlikle bunları kullanmadığını söyleyemem,

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.