Bir sınıf için ne kadar büyük?


29

Uzun zamandır geliştiriciyim (49 yaşındayım) ama nesne odaklı geliştirmede yeniyim. Bertrand Meyer’in Eiffel’inden beri OO hakkında okudum, ancak çok az OO programlaması yaptım.

Mesele şu ki, OO tasarımındaki her kitap, bir tekne, araba veya çok sık kullandığımız ortak nesnelerden bir örnekle başlar ve öznitelikler ve yöntemler eklemeye başlar ve nesnenin durumunu nasıl modellediklerini ve ne ile yapılabileceğini açıklar. o.

Bu yüzden genellikle "model ne kadar iyi olursa uygulamadaki nesneyi ne kadar iyi temsil ederse ve sonuç o kadar iyi çıkar" gibi bir şeye giderler.

Şimdiye kadar çok iyi, ama diğer taraftan, “bir sınıf sadece tek bir sayfaya sığmalı” gibi tarifler veren birkaç yazar buldum (şimdi ne denemek istediğimize “hangi monitör boyutuna?” Eklerdim. kodu yazdırmak için!).

Örneğin PurchaseOrder, davranışını kontrol eden sınırlı bir durum makinesine sahip olan bir sınıfı ve PurchaseOrderItemburadaki çalışmadaki argümanlardan birisini, PurchaseOrderbazı yöntemlerle (bir veri sınıfından biraz daha fazla) basit bir sınıf kullanmamız gerektiği ve PurchaseOrderFSMsonlu durum makinesini kullanan bir “uzman sınıfı” PurchaseOrder.

Bunun, Jeff Atwood'un Kod Kokuları'ndaki Kod Yazma Korkusuyla ilgili mesajında ​​“Özellik Envy” veya “Uygunsuz samimiyet” sınıfına girdiğini söyleyebilirim . Ben sadece sağduyu derdim. Ben verebilir Eğer onaylamak veya benim gerçek satın alma siparişi iptal sonra PurchaseOrdersınıf olmalı issuePO, approvePOve cancelPOyöntemleri.

Bu, OO'nun temel taşları olarak anladığım “bağdaştırmayı maksimize et” ve “eşleşmeyi minimize et” asırlık ilkeleri ile uyumlu değil mi?

Ayrıca, bu sınıfın korunmasına yardımcı olmuyor mu?


17
Yazı tipini yöntem adına kodlamak için hiçbir neden yoktur. Eğer varsa Yani PurchaseOrder, sadece yöntemleri sayabilirim issue, approveve cancel. POEki yalnızca negatif bir değer katar.
çizgi-tom-bang

2
Kara delik yöntemlerinden uzak durduğunuz sürece , iyi olmalısınız. :)
Mark C,

1
Mevcut ekran çözünürlüğümle 145 karakter genişliğinde diyebilirim.
DavRob60

Yorumlarınız için herkese teşekkürler, bu konuda bana gerçekten yardımcı oldular. Bu site izin verseydi, TMN ve lazarus'un cevabını da seçerdim, ama sadece bir tanesine izin verirdi, o yüzden Craig'e gitti. Saygılarımla.
Miguel Veloso

Yanıtlar:


27

Bir sınıf, Tek Sorumluluk İlkesini kullanmalıdır. Gördüğüm en büyük sınıfların çoğu bu yüzden çok büyük. Her bir yönteme bakın ve kodun bu sınıfta mı yoksa ayrı mı olduğuna karar verin, yinelenen kod ipucudur. Bir problemPO yönteminiz olabilir, ancak örneğin 10 satırlık veri erişim kodu içeriyor mu? Bu kod muhtemelen orada olmamalıydı.


1
Craig, Tek Sorumluluk Prensibi'nin farkında değildim ve okudum. Aklıma ilk gelen, Sorumluluğun kapsamı nedir? Bence bir PO için durumunu yönetiyor ve bu da POO, onaylamaPO ve cancelPO yöntemlerinin nedenidir, ancak PO öğesinin durumunu idare eden PurchaseOrderItem sınıfıyla etkileşimi de içerir. Dolayısıyla, bu yaklaşımın SRP ile tutarlı olup olmadığını netleştiremiyorum. ne söylerdin
Miguel Veloso

1
Çok güzel ve özlü bir cevap için +1. Gerçekçi olarak, bir sınıfın ne kadar büyük olması gerektiği konusunda kesin bir ölçü olamaz. SRP'yi uygulamak, sınıfın yalnızca olması gerektiği kadar büyük olmasını sağlar.
S.Robins

1
@MiguelVeloso - Bir PO'nun onaylanmasının muhtemelen bir PO vermekten farklı bir mantığı ve kuralları vardır. Eğer öyleyse, sorumlulukları bir POA onaylayıcısı ve bir POI sunucusuna ayırmak mantıklıdır. Fikir şu ki, kurallar bir için değişirse, neden diğerini içeren sınıfla uğraşmak istiyorsunuz?
Matthew Flynn

12

Benim düşünceme göre sınıf büyüklüğü değişkenler, fonksiyonlar ve yöntemler söz konusu sınıfla alakalı olduğu sürece önemli değildir.


1
Öte yandan, büyük boyut bu yöntemlerin muhtemelen söz konusu sınıfla ilgili olmadığını göstermektedir.
Billy ONeal

5
@Billy: Büyük sınıfların kod kokusu olduğunu söyleyebilirim ama otomatik olarak kötü değiller.
David Thornley

@David: Bu yüzden orada "muhtemelen" kelimesi var - bu önemli :)
Billy ONeal 14:10

Kabul etmemeliydim ... Oldukça tutarlı bir adlandırma kuralı olan bir proje üzerinde çalışıyorum. Sadece çok büyük :)
Jay

2
Biri bir sınıfın arasında sorumluluklar kısıtlamak etmezse sınıfa uygun olmaktan çok değişken, fonksiyonlar ve yöntemler olacak - - "Cehenneme giden yol" gider tam olarak nasıl Bu cevap şovları ve bu potansiyel müşteriler kolaylıkla sahip çok birçoğu.
Doktor Brown

7

Büyük sınıflarla ilgili en büyük sorun, bu sınıfları test etme veya diğer sınıflarla etkileşimi söz konusudur. Büyük sınıf mevcudu tek başına bir sorun değildir, ancak tüm kokularda olduğu gibi, potansiyel bir sorun olduğunu gösterir . Genel olarak konuşursak, sınıf büyük olduğunda, sınıfın tek bir sınıftan daha fazlasını yaptığını gösteren bir göstergedir.

Otomobil analojiniz için, eğer sınıf carçok büyükse, bu muhtemelen sınıf engine, sınıf doors ve sınıf windshields gibi bölümlere ayrılması gerektiğini gösterir .


8
Ve bir Otomobilin Araç arayüzünü uygulaması gerektiğini unutmayalım. :-)
Chris

7

Çok büyük bir sınıfın belirli bir tanımı olduğunu sanmıyorum. Ancak, sınıfımı yeniden düzenlemem mi yoksa sınıfın kapsamını yeniden tanımlamam mı gerektiğini belirlemek için aşağıdaki yönergeleri kullanırdım:

  1. Birbirinden bağımsız birçok değişken var mı? (Kişisel toleransım çoğu durumda yaklaşık 10 ~ 20'dir)
  2. Köşe durumlarda için tasarlanmış birçok yöntem var mı? (Kişisel toleransım ... şey, bu benim ruh halime bağlı.

1 ile ilgili olarak, ön cam boyutunuzu, tekerlek boyutunu, arka lamba modelini ve sınıfınızdaki diğer 100 ayrıntıyı tanımladığınızı hayal edin car. Hepsi araba ile “alakalı” olsalar da, bu sınıfın davranışını izlemek çok zor car. Ve bir gün meslektaşınız yanlışlıkla (veya bazı durumlarda, kasıtlı olarak) arka lamba modeline dayanarak ön cam boyutunu değiştirdiğinde, ön camın neden aracınıza artık sığmadığını bulmak sonsuza dek sürecektir.

2 ile ilgili olarak, bir otomobilin sınıfta sahip olabileceği tüm davranışları tanımlamaya çalıştığınızı car, ancak car::open_roof()yalnızca dönüştürülebilir ürünler için car::open_rear_door()geçerli olacağını ve bu 2 kapılı araçlar için geçerli olmadığını düşünün . Cabriolar ve 2 kapılı otomobiller tanım olarak "otomobil" olsalar da, bunları sınıfta uygulamak sınıfı carzorlaştırıyor. Sınıf kullanımı zorlaşır ve bakımı zorlaşır.

Bu 2 kılavuzun dışında, sınıf kapsamının açık bir tanımını önerebilirim. Kapsamı tanımladıktan sonra, sınıfı kesinlikle tanımı temel alarak uygulayın. Çoğu zaman insanlar, kapsamın zayıf tanımından veya sınıfa eklenen keyfi özelliklerden dolayı "çok büyük" bir sınıf alırlar


7

İhtiyacınız olanı 300 satırda söyleyin

Not: Bu kural, kendi başına iyi bir idame edilebilirlik fikri olan 'dosya başına bir sınıf' yaklaşımını takip ettiğinizi varsaymaktadır.

Bu kesin bir kural değil, ancak bir sınıfta 200'den fazla kod satırı görürsem şüpheliyim. 300 hat ve uyarı zilleri yanıyor. Başkasının kodunu açıp 2000 satır bulduğumda, ilk sayfayı bile okumadan zamanın yeniden canlandığını biliyorum.

Çoğunlukla bu sürdürülebilirlik için aşağı gelir. İtirazınız o kadar karmaşıksa, davranışını 300 satırda ifade edemezsiniz, başkasının anlaması çok zor olacaktır.

Bu kuralı, bir UI sayfası için 'davranış nesnesi' oluşturduğum Model -> ViewModel -> View dünyasında bükdüğümü buluyorum çünkü genellikle davranışların tamamını açıklamak için 300'den fazla satır alır Bir sayfa. Bununla birlikte, bu programlama modelinde hala yeniyim ve sayfalar / görünüm modelleri arasındaki davranışları yeniden görüntülemek / yeniden kullanmak için iyi bir yol buluyorum, bu durum ViewModels'imin boyutunu yavaş yavaş azaltıyor.


Kişisel rehberim de yaklaşık 300 satırdır. +1
Marcie

Bence OP bir buluşsal buluş arıyor ve bu da iyi bir şey.
neontapir

Teşekkürler, kesin sayıları kılavuz olarak kullanmak değerlidir.
Sheppard

6

Geriye dönelim:

Bu, OO'nun temel taşları olarak anladığım “bağdaştırmayı maksimize et” ve “eşleşmeyi minimize et” asırlık ilkeleri ile uyumlu değil mi?

Aslında, OO'nun sadece bir paradigmadan başka bir programlama temel taşıdır.

Antoine de Saint-Exupéry'in sorunuzu cevaplamasına izin vereceğim (çünkü ben tembelim;)):

Kusursuzluk, eklenecek başka bir şey olmadığında değil, alınacak bir şey kalmadığında da başarılır.

Sınıf ne kadar basit olursa, o kadar doğru olursunuz, tam olarak test etmek o kadar kolay olur.


3

Feature Envy sınıflandırmasında OP ile birlikteyim. Hiçbir şey beni başka bir sınıfın içindekiler üzerinde çalışan bir grup metotla bir grup sınıfa sokmaktan daha fazla rahatsız edemez. OO, verileri ve bu verilerdeki işlemleri modellemenizi önerir. Bu, işlemleri verilerden farklı bir yere koymanız anlamına gelmez! Verileri ve bu yöntemleri bir araya getirmeye çalışıyor .

İle carve personmodelleri Hakim nedenle, bu içine, elektriksel bir bağlantı kurmak, hatta marş iplik için kod koyarak gibi olur personsınıfa. Bunun, deneyimli bir programcı için açıkça yanlış olacağını umuyorum .

Gerçekten ideal bir sınıfa veya yöntem boyutuna sahip değilim, ancak yöntem ve işlevlerimi bir ekrana sığdırmayı tercih ediyorum, böylece hepsini bir yerde görebiliyorum. (Vim'in basılı bir sayfadaki satır sayısının tam çevresinde olduğu 60 satırlık bir pencere açacak şekilde yapılandırılmış olduğunu var.) Bunun pek bir anlam ifade etmeyeceği yerler var, ama benim için çalışıyor. Sınıf tanımları için aynı rehberi izlemeyi seviyorum ve dosyalarımı birkaç "sayfa" altında tutmaya çalışıyorum. 300'den fazla olan herhangi bir şey, 400 satır tuhaf hissetmeye başlar (çoğunlukla sınıfın çok fazla doğrudan sorumluluk üstlenmeye başlamasından dolayı).


+1 - iyi kurallar var ama bu konuda otoriter olmamak. Ancak, bir sınıfın dağılmasının, farklı sınıfların birbirlerinin özel üyelerine dokunması gerektiği anlamına gelmediğini söyleyebilirim.
Billy ONeal

Farklı sınıfların birbirlerinin özel bölümlerine asla dokunması gerektiğini düşünmüyorum. 'Arkadaş' erişimi bir şeyi kurmak ve çalıştırmak için uygun olsa da, (benim için) daha iyi bir tasarıma adım atmak bir taş. Genelde erişimcilerden de kaçınırım, çünkü başka bir sınıfın içlisine bağlı olarak başka bir Kod Kokusu var .
dash-tom-bang

1

Bir sınıf tanımının birkaç yüz yöntemi olduğunda, çok büyüktür.


1

Sınıflar için tek sorumluluk ilkesinin kullanılmasına tamamen katılıyorum, ancak eğer takip edilirse ve büyük sınıflarla sonuçlanırsa, öyle olsun. Asıl odak noktası, bireysel yöntemlerin ve özelliklerin çok büyük olmaması gerektiği , siklomatik karmaşıklığın oradaki rehber olması ve ardından genel sınıf boyutunu artıracak ancak onu okunaklı ve test edilebilir bir seviyede bırakacak birçok özel yöntemle sonuçlanabilecek yol gösterici olması gerekir. Kod okunabilir kalırsa, boyut önemsizdir.


1

Bir satınalma siparişi vermek genellikle satınalma siparişinden daha fazlasını içeren karmaşık bir işlemdir. Bu durumda, iş mantığını ayrı bir sınıfta tutmak ve satınalma siparişini daha basit hale getirmek muhtemelen yapılacak doğru şeydir. Genel olarak, yine de haklısın - "veri yapısı" dersleri istemiyorsun. Örneğin, "POManager" işletme sınıfı ' issue()yönteminiz, muhtemelen PO issue()yöntemini çağırmalıdır . PO daha sonra durumunu "İhraç Edildi" olarak ayarlayabilir ve sorun tarihini not edebilir, POManager daha sonra fatura beklemelerini bildirmek için ödenecek hesaplara bir bildirim gönderebilir ve envanterine başka bir bildirim gelmesini sağlar. beklenen tarih.

Yöntem / sınıf büyüklüğü için "kuralları" zorlayan hiç kimse gerçek dünyada yeterince zaman harcamamış. Diğerlerinin de belirttiği gibi, bu genellikle bir yeniden değerlendirme göstergesidir, ancak bazen (özellikle "veri işleme" tipi çalışmalarda), 500'den fazla satır içeren tek bir yöntemle bir sınıf yazmanız gerekir. Asma onu.


Sanırım POManager "kontrolcü" olur ve PurchaseOrder MVC modelindeki "model" olur, değil mi?
Miguel Veloso

0

“Bir sınıf sadece bir sayfaya sığmalı” gibi tarifler veren birkaç yazar buldum.

Bir sınıfın sadece fiziksel büyüklüğü açısından, büyük bir sınıfı görmek kod kokusunun bir göstergesidir, ancak mutlaka her zaman koku olduğu anlamına gelmez. (Genellikle öyledirler) Karayip Korsanları'ndaki korsanların söylediği gibi, "kurallar" dediğiniz şey, gerçek kurallardan daha fazla. Bir keresinde "bir sınıfta en fazla 100 LOC" yu bir kez daha izlemeye çalıştım ve sonuçta gereksiz bir fazla mühendislik çalışması yapıldı.

Bu yüzden genellikle "model ne kadar iyi olursa uygulamadaki nesneyi ne kadar iyi temsil ederse ve sonuç o kadar iyi çıkar" gibi bir şeye giderler.

Tasarımlarıma genellikle bununla başladım. Bu sınıf gerçek dünyada ne yapar? Sınıfım bu amacı gereksinimlerinde belirtildiği gibi nasıl yansıtmalıdır? Buraya bir miktar durum ekliyoruz, oradaki bir alan, bu alanlar üzerinde çalışmak için bir yöntem, birkaç tane daha ekleyin ve işte! Bir işçi sınıfımız var. Şimdi imzaları doğru uygulamalarla doldurun, biz de iyiyiz, öyle düşünüyorsunuz. Şimdi ihtiyacımız olan tüm işlevsellik ile iyi ve büyük bir sınıfa sahibiz. Ancak bununla ilgili sorun, gerçek dünyanın hesaba katma şeklini almıyor. Ve bununla demek istediğim "DEĞİŞTİR" olarak dikkate alınmaz.

Sınıfların tercihen daha küçük parçalara bölünmesinin nedeni, daha sonra mevcut mantığı etkilemeden ya da istemeden yeni bir hata vermeden veya büyük bir kısmı iki kere eklemeden büyük sınıfları değiştirmek veya sadece yeniden kullanımı zorlaştırmaktır. Refactoring, design patterns, SOLID, vb. Devreye giriyor ve sonuç ise genellikle diğer daha küçük, daha granül alt sınıflarda çalışan küçük bir sınıf.

Ayrıca, örneğinizde, PurchaseOrder sınıfına IssuePO, ApprovePO ve Cancel PO eklemek, mantıksız görünüyor. Satınalma Siparişleri, kendilerini yayınlamaz, onaylamaz veya iptal etmez. Eğer PO metotlara sahipse, metotlar bir bütün olarak sınıfta değil, durum üzerinde çalışmalıdır. Onlar gerçekten sadece diğer sınıfların üzerinde çalıştığı veri / kayıt sınıflarıdır.


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.