Sınıf yöntemi tanımlarını sipariş etmenin en insan dostu yolu mu?


38

Herhangi bir sınıf tanımında, çeşitli şekillerde sıralanan yöntem tanımlarını gördüm: alfabetik, en yaygın kullanıma dayalı kronolojik, görünürlükle alfabetik olarak gruplandırılmış, alıcılar ve birlikte gruplandırılmış harflerle alfabetik, vb. Yeni bir sınıf yazmaya başladığımda, Ben sadece her şeyi yazmaya meyilliyim, sonra da tüm sınıfı yazmayı bitirince yeniden sıraladım. O notta üç sorum var:

  1. Sipariş önemli mi?
  2. "En iyi" sipariş var mı?
  3. Sanırım yok, farklı sıralama stratejilerinin artıları ve eksileri neler?

1
İnsanların sadece yöntemleri yeniden düzenlemek için kodları kesip yapıştırmalarını beklemiyorsunuz. IDE otomatik olarak yaparsa, o zaman para cezası. Aksi takdirde zorlamak zordur.
Reacgular

Açıklığa kavuşturmak için sorum, sözdizimi değil okunabilirlik / kullanılabilirlikle ilgilidir.
Johntron

Yanıtlar:


52

Bazı programlama dillerinde, sipariş önemlidir, çünkü ilan edilene kadar işleri kullanamazsınız. Ancak bunun dışında çoğu dil için derleyici için farketmez. Öyleyse, insanlara önem vermekten vazgeçtin.

En sevdiğim Martin Fowler alıntı: Any fool can write code that a computer can understand. Good programmers write code that humans can understand.Sınıfınızın sıralamasının insanların anlamasını kolaylaştıran şeylere bağlı olması gerektiğini söyleyebilirim.

Ben şahsen Bob Martin'in Clean Codekitabında verdiği düşürücü tedaviyi tercih ediyorum . Sınıfın en üstündeki üye değişkenler, ardından yapıcılar, sonra diğer tüm yöntemler. Ve bu yöntemlerin sınıf içinde nasıl kullanıldığına yakın bir şekilde yaklaşmasını emredersiniz (keyfi bir şekilde herkesi daha sonra özel ve sonradan korunmak yerine). Buna "dikey mesafeyi" veya bunun gibi bir şeyi en aza indirgeme diyor (şu anda üzerimde kitap yok).

Düzenle:

"Dikey mesafe" nin temel fikri, insanların sadece kaynak kodunuzun etrafından dolaşmasını sağlamaktır. İşler birbiriyle ilgiliyse birbirine yakın olmalılar. İlgisiz şeyler daha uzak olabilir.

Temiz Kod'un 5. Bölümü (büyük kitap, btw), Bay Martin'in sipariş kodunu nasıl önerdiği konusunda bir ton ayrıntılı bilgi veriyor. Okuma kodunun bir gazete makalesini okumak gibi çalışması gerektiğini önerir: üst düzey detaylar önce gelir (en üstte) ve okudukça daha fazla ayrıntı alırsınız. “Eğer bir işlev diğerini çağırırsa, dikey olarak yakın olmalı ve eğer mümkünse arayan arayan ucunun üzerinde olmalıdır” diyor. Ek olarak, ilgili kavramlar birbirine yakın olmalıdır.

İşte burada, birçok yönden kötü olan (zayıf OO tasarımı; asla doublepara için kullanmayın ) fakat fikri açıklayan bir örnek var :

public class Employee {
  ...
  public String getEmployeeId() { return employeeId; }
  public String getFirstName() { return firstName; }
  public String getLastName() { return lastName; }

  public double calculatePaycheck() {
    double pay = getSalary() / PAY_PERIODS_PER_YEAR;
    if (isEligibleForBonus()) {
      pay += calculateBonus();
    }
    return pay;
  }

  private double getSalary() { ... }

  private boolean isEligibleForBonus() {
    return (isFullTimeEmployee() && didCompleteBonusObjectives());
  }

  public boolean isFullTimeEmployee() { ... }
  private boolean didCompleteBonusObjectives() { ... }
  private double calculateBonus() { ... }
}

Metotlar emredildi, böylece onları en baştan aşağıya çağıran, onları arayanlara yakınlar. Tüm privateyöntemleri bu yöntemlerin altına publickoysaydık, programın akışını takip etmek için daha çok zıplamanız gerekir.

getFirstNameve getLastNamekavramsal olarak ilişkilidir (ve getEmployeeIdmuhtemelen de öyle), bu yüzden birbirlerine yakınlar. Hepsini aşağıdan aşağıya doğru hareket ettirebilirdik, ama getFirstNameyukarıdan ve getLastNameaşağıdan görmek istemeyiz .

Umarım bu size temel bir fikir verir. Bu tür bir şeyle ilgileniyorsanız, okumanızı şiddetle tavsiye ederim Clean Code.


Örnek değişkenlerin ayarlayıcılarının ve alıcılarının nasıl yerleştirilmesi gerektiğini bilmem gerekiyor. Sınıf kurucusundan hemen sonra mı yoksa sınıfın altında mı olmalı?
srinivas

Şahsen ben kurucudan sonra üstte onları seviyorum. Ancak bu gerçekten önemli değil; Karar vermenin iyi bir yolu olarak projenizde ve ekibinizde tutarlılığı öneririm.
Allan

Olmamalı calculateBonus()önce gelir isFullTimeEmployee()ve didCompleteBonusObjectives()?
winklerrr

@ winklerrr Bunun için bir argüman görebilirim. Ben çünkü yaptığım yerde yerleştirdiler isFullTimeEmployeeve didCompleteBonusObjectiveskullandığı isEligibleForBonusdikey kendisine yakın olmak onlar gerektiğini böylece. Ancak calculateBonus, çağrıldığı yere daha yakın olması için potansiyel olarak hareket edebilirsiniz . Ne yazık ki, işlevleri çağıran işlevler olduğundan, sonunda mükemmel bir siparişin olmadığı sorunlarla (birden fazla kişi tarafından adlandırılan paylaşılan işlevler gibi) karşılaşırsınız. O zaman en iyi kararını bıraktı. Bu sorunları azaltmak için sınıfların ve işlevlerin küçük tutulması önerilir.
Allan

2

Yöntemlerimi genellikle ilişkiye ve kullanım sırasına göre sıralıyorum.

Bir ağ kursu al, tüm TCP yöntemlerini birlikte gruplayacağım, sonra tüm UDP yöntemlerini birlikte. TCP'nin içindekiler ilk olarak kurulum yöntemine sahip olur, belki ikinci bir mesaj gönderir ve tcp soketini üçüncü olarak kapatır.

Açıkçası, tüm sınıflar bu modele sığmayacak, ama bu benim genel iş akışım.

Her şeyden çok hata ayıklamak için bu şekilde yapıyorum, bir sorunum olduğunda ve yönteme atlamak istediğimde, nasıl yazıldığını sanmıyorum, bunun neden sorumlu olduğunu düşünüyorum ve o bölüme gidiyorum.

Bu şekilde özellikle, kodunuzu birlikte gruplandırılmış olarak görüntüleyen / kullanan üçüncü bir tarafa anlam ifade eder ve kullanıldığı sırayı takip eder, böylece sınıfınızla birlikte yazacakları kod, sınıfla aynı yapıyı takip eder.

Bu konuda önemli mi?

kesinlikle okunabilirlik için.

bunun dışında, gerçekte olmayan, yalnızca belirli dillerin, yukarıda belirtilenler yerine vb.


0

İdeal olarak, sınıflarınız farketmeyecek kadar küçüktür. Yalnızca bir düzine yönteminiz varsa ve editörünüz veya IDE'niz katlanmayı destekliyorsa, bir sorunla karşılaşmazsınız, çünkü tüm yöntemler listesi 12 satıra sığar.

Bunu başaramazsa, üst düzey ayrım kamu ile özel arasında olmalıdır. İlk önce genel yöntemleri listeleyin: bunlar insanların en çok aradığı şeylerdir, çünkü sınıfınızın kod tabanının geri kalanıyla etkileşime girme yolunu tanımlarlar.

Daha sonra, bunların her birinde, yöntemleri işlevselliğe göre gruplamak en mantıklı olanıdır: bir blokta yapıcılar ve yıkıcılar, diğerlerinde alıcı / ayarlayıcılar, operatör aşırı yüklenmeleri, statik yöntemler ve grubun geri kalanı. C ++ 'ta operator=kuruculara yakın durmayı seviyorum , çünkü bu kopya kurucu ile yakından ilgili ve aynı zamanda varsayılan ctorun (veya hiçbirinin) varsayılan ctor, copy ctor, operator = ve dtor olup olmadığını hızlı bir şekilde tespit edebilmek istiyorum. var olmak.


-1

tl; Dr.

Yalnızca çalıştığınız dil belirli bir düzen gerektiriyorsa. Bunun dışında, sipariş size kalmış. Tutarlı ve mantıklı bir sistem seçin ve mümkün olduğunca ona bağlı kalmaya çalışın.


1. Sipariş önemli mi?

Yalnızca çalıştığınız dilin, bu örnekte olduğu gibi, dosyada çağrıldığı yerden daha önce tanımlanmış bir işlevi olması gerekiyorsa:

void funcA()
{
   funcB();
}

void funcB()
{
   //do something interesting...
}

Bir hata alırsınız çünkü funcB()kullanmadan önce ararsınız. Bunun PL / SQL’de ve muhtemelen C’de de bir sorun olduğunu düşünüyorum, ancak aşağıdaki gibi ileri bildirimlerde bulunabilirsiniz:

void funcB();

void funcA()
{
   funcB();
}

void funcB()
{
   //do something interesting...
}

Siparişin "yanlış" olması durumunda derleyemeyeceğiniz yeri düşünebildiğim tek durum budur.

Aksi takdirde, istediğiniz zaman istediğiniz zaman yeniden sipariş verebilirsiniz. Muhtemelen bunu yapmak için bir araç bile yazabilirsiniz (eğer orada bir tane bulamazsanız).

2. "En iyi" sipariş var mı?

Dil / ortamın sipariş gereksinimleri yoksa, "en iyi" sipariş sizin için en uygun olandır . Benim için tüm alıcıları / alıcıları genellikle sınıfın başında (ancak kurucular / statik başlatıcılardan sonra) ve sonra özel yöntemler, sonra korunan, sonra halka açık tutmayı seviyorum. Her kapsam temelli grupta genellikle sipariş yoktur , ancak aşırı yüklenmiş yöntemler, parametre sayısını sırayla tutmaya çalışırım. Ayrıca, ilişkili işlevsellik ile yöntemleri bir arada tutmaya çalışıyorum, ancak bazen bunu yapmak için kapsam tabanlı siparişlerimi kırmam gerekiyor; ve bazen kapsam-temelli siparişleri grup bazında işlevselliği bozmaya çalışmak. Ve IDE'm bana alfabetik bir taslak görünümü verebilir, yani bu da iyidir. ;)

C # gibi bazı diller, derleme üzerinde bir etkisi olmayan ancak ilgili işlevleri bir arada tutmayı kolaylaştırabilecek, daha sonra IDE ile gizleyebilecek / görüntüleyebilecek olan "bölgelerdeki" kodları gruplama yeteneğine sahiptir . MainMa'nın işaret ettiği gibi , bunun kötü bir uygulama olduğunu düşünen bazı kişiler var. Bu şekilde kullanılan bölgelerin iyi ve kötü örneklerini gördüm, bu yoldan gidecekseniz dikkatli olun.

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.