Aşırı yükleme Açık / kapalı prensibine bir örnek midir?


12

Wikipedia diyor

"yazılım varlıkları (sınıflar, modüller, işlevler, vb.) genişletme için açık, ancak değişiklik için kapalı olmalıdır"

Kelime fonksiyonları gözlerimi yakaladı ve şimdi bir yöntem için aşırı yük oluşturmanın Açık / kapalı prensibinin bir örneği olarak kabul edilebileceğini varsayabilir miyiz acaba?

Bir örnek açıklayayım. Hizmet katmanınızda neredeyse 1000 yerde kullanılan bir yönteminiz olduğunu düşünün. Yöntem userId'yi alır ve kullanıcının yönetici olup olmadığını belirler:

bool IsAdmin(userId)

Şimdi, kullanıcının kullanıcı adına göre değil, kullanıcı adına göre yönetici olup olmadığını belirlemenin gerekli olduğunu düşünün. Yukarıda belirtilen yöntemin imzasını değiştirirsek, kodu 1000 yerde kırdık (işlevler modifikasyona kapatılmalıdır). Böylece, kullanıcı adını almak, kullanıcı adını ve orijinal yönteme göre userId'yi bulmak için bir aşırı yük oluşturabiliriz:

public bool IsAdmin(string username)
{
    int userId = UserManager.GetUser(username).Id;
    return IsAdmin(userId);
}

Bu şekilde, bir aşırı yük oluşturarak işlevimizi genişlettik (işlevler uzantıya açık olmalıdır).

Açık / kapalı prensip örneği mi?

Yanıtlar:


5

Şahsen wiki ifadesini bu şekilde yorumluyorum:

  • bir sınıf için: sınıfı devralmaktan ve işlevselliğini geçersiz kılmaktan veya genişletmekten çekinmeyin , ancak orijinal sınıfı hacklemeyin, böylece yaptıklarını değiştirin .
  • bir modül için (örneğin bir kütüphane): orijinali saran, işlevleri kullanımı daha kolay sürümlerle birleştiren veya orijinali ekstra özelliklerle genişleten , ancak orijinal modülü değiştirmeyen yeni bir modül / kütüphane yazmaktan çekinmeyin .
  • bir işlev için (yani bir statik yöntem değil, bir sınıf yöntemi): örneğin benim için makul; orijinal IsAdmin (int) işlevini yeni IsAdmin (dize) içinde yeniden kullanın. orijinal değişmez, yeni işlev işlevselliğini genişletir.

ancak buradaki adım, kodunuz IsAdmin (int) 'in bulunduğu' cUserInfo 'sınıfını kullanıyorsa, esas olarak kuralı ihlal etmeniz ve sınıfı değiştirmenizdir. kural ne yazık ki yeni bir sınıf cUserWithNameInfo: public cUserInfo sınıfı yaptıysanız ve IsAdmin (string) geçersiz kılındı. Eğer kod tabanına sahip olsaydım asla kurala uymazdım. Ben bollocks söyleyebilirim ve sadece önerdiğin değişikliği yap.


3

Öncelikle, örneğin maalesef örneği var. Bunu gerçek dünyada asla yapmazsınız, çünkü gereksiz bir çifte kazanıma neden olur. Daha da kötüsü, kullanıcı kimliği ve kullanıcı adı bir noktada aynı tür olabilir. Ziyade

public bool IsAdmin(int userid)
{
    User user = UserManager.GetUser(userid);
    return user.IsAdmin();
}

public bool IsAdmin(string username)
{
    int userId = UserManager.GetUser(username).Id;
    return IsAdmin(userId);
}

O sınıfı gerçekten genişletmelisin .

public bool IsAdmin(int userid)
{
    User user = UserManager.GetUserById(userid);
    return user.IsAdmin();
}

public bool IsUsernameAdmin(string username)
{
    User userId = UserManager.GetUserByName(username);
    return user.IsAdmin();
}

Ayrıca tutarlılık için ilk yöntem adını IsUserIdAdmin olarak yeniden düzenleyebilir ve değiştirebilirsiniz, ancak bu gerekli değildir. Mesele şu ki, yeni yöntemi eklerken ve hiçbir arama kodunun bozulmadığını garanti ederken, sınıfınızı genişletilebilir buldunuz. Başka bir deyişle, uzantıya açıktır .

Ve işte açık-kapalı prensibi. Kodunuzun bir kısmını genişletmeye ve kendinizi değiştirmek zorunda kalmaya çalışana kadar (bununla birlikte artan riskle) bulana kadar kodunuzun ne kadar iyi uyduğunu asla bilemezsiniz . Ancak, deneyimle, tahmin etmeyi öğrenirsiniz.

As Bob amca diyor (vurgu benim):

Kapanış tamamlanamayacağı için stratejik olmalı. Yani, tasarımcı tasarımını kapatmak için hangi tür değişiklikleri yapması gerektiğini seçmelidir. Bu, deneyimden elde edilen belli bir miktar önseziyi gerektirir . Deneyimli tasarımcı, kullanıcıları ve sektörü farklı türdeki değişikliklerin olasılığını değerlendirecek kadar iyi tanır. Daha sonra açık-kapalı prensibinin en olası değişiklikler için çağrıldığından emin olur.


İyi açıklamanız için teşekkürler. Ancak 1000 gidiş-dönüş veya bir gidiş-dönüş yapmak burada ana nokta değildir. Böylece şu anda performansı unutalım. Ancak, yaptığım şey sınıfı genişletmekti, çünkü aynı ada sahip, ancak farklı giriş parametreleriyle başka bir yöntem ekledim. Ama Bob amcadan aldığın teklifi gerçekten takdir ettim . +1. ;)
Saeed Neamati

@SaeedNeamati: Belirttiğim nokta, mevcut bir yöntemi kullanan bir yöntem eklemenin veya sınıfınızın uzantıya açık olduğu her durumda tamamen bağımsız bir yöntem eklemenin önemli olmamasıdır. Ancak, bunu başarmak için mevcut yöntem arayüzünü değiştirmeniz gerekiyorsa, değişiklik yapmaya kapalı olmazsınız.
pdr

2

Açık-kapalı prensibine uyan modüllerin iki temel özelliği vardır.

  1. Bunlar “Uzantıya Aç” dır. Bu, modülün davranışının genişletilebileceği anlamına gelir. Uygulamanın gereksinimleri değiştikçe veya yeni uygulamaların gereksinimlerini karşılamak için modülün yeni ve farklı şekillerde davranmasını sağlayabiliriz.
  2. “Modifikasyona Kapalı”. Böyle bir modülün kaynak kodu dokunulmazdır. Hiç kimsenin kaynak kodda değişiklik yapmasına izin verilmez.
  1. Yönteminizi aşırı yükleyerek mevcut modülün işlevselliğini genişletiyorsunuz, böylece uygulamanızın yeni ihtiyaçlarını karşılıyorsunuz

  2. Varolan bir yöntemde değişiklik yapmıyorsunuz, bu nedenle ikinci kuralı ihlal etmiyorsunuz.

Orijinal yöntemin değiştirilmesine izin vermeme konusunda başkalarının söylediklerini duymak isterim. Evet, uygun erişim değiştiricileri koyabilir ve kapsüllemeyi zorunlu kılabilirsiniz, ancak başka ne yapılabilir?

Ref: http://www.objectmentor.com/resources/articles/ocp.pdf


1

Açık-Kapalı Prensip her zaman bir gerçeklik değil, bir amaç, ideal bir durumdur. Özellikle eski kodu yeniden gözden geçirmek için ilk adım, OCP'yi bir olasılık haline getirmek için genellikle ağır değişikliktir. İlkenin kökü, çalışma kodunun zaten çalıştığı ve değiştirmenin muhtemelen hataları tanıtmasıdır. Bu nedenle en iyi senaryo mevcut kodu değiştirmek değil, sadece yeni kod eklemek.

Ama diyelim ki adlı bir fonksiyonunuz var BigContrivedMethod(int1, int2, string1). BigContrivedMethodüç şey yapar: şey1, şey2 ve şey3. Bu noktada, BCM'yi tekrar kullanmak muhtemelen zordur, çünkü çok fazla şey yapar. İçine (eğer mümkünse) o üstlenmeden ContrivedFunction1(int), ContrivedFunction2(int)ve ContrivedFunction3(string)daha kolay birleştirebilirsiniz o üç küçük, daha odaklı yöntemler verir.

Bu yöntem / işlevler açısından kompozisyonun OCP'nin anahtarıdır: kompozisyon. Diğer işlevlerden çağırarak işlevleri "genişletirsiniz".

OCP'nin diğer 5 ilkenin, SOLID yönergelerinin bir parçası olduğunu unutmayın. İlki anahtardır, Tek Sorumluluk. Kod tabanınızdaki her şey yapması gereken tek bir şey yaptıysa, kodu asla değiştirmeniz gerekmez. Yalnızca yeni kod eklemeniz veya eski kodu yeni yöntemlerle birleştirmeniz gerekir. Gerçek kod nadiren bu yönergeyi karşıladığından, OCP'yi almadan önce SRP'yi almak için sık sık değiştirmeniz gerekir.


Sanırım burada Tek Sorumluluk Müdürü hakkında konuşuyorsunuz, OCP'den değil.
Saeed Neamati

1
SRP olmadan gerçekçi bir şekilde OCP'ye sahip olamayacağınızı söylüyorum. Çok fazla kod genişletilemez, tekrar kullanılamaz. SOLID neredeyse önem sırasına göre yazılmıştır, her ilke uygulanabilirden önce olanlara dayanmaktadır.
CodexArcanum

Bu cevap daha fazla kaldırılmalıdır.
Ashish Gupta

0

Programınızın davranışını eski kodu değiştirmek yerine yeni kod yazarak değiştiriyorsanız, açık-kapalı ilkesini izlersiniz.

Olası her değişikliğe açık kod yazmak oldukça imkansız olduğundan (ve analiz felci girdiğiniz için istemiyorsanız), üzerinde çalışmakta olduğunuz tüm farklı davranışlara değişiklik yapmak yerine uzantıya yanıt veren bir kod yazarsınız.

Değiştirmeniz gereken bir şeyle karşılaştığınızda, yeni davranışa izin vermek için bir şeyi değiştirmek yerine, değişiklik noktasının ne olduğunu anlarsınız, programınızı davranışını değiştirmeden yeniden yapılandırırsınız, böylece bu davranışı YENİ kod yazarak değiştirebilirsiniz .

Peki, bu sizin davanız için nasıl geçerlidir:

Sınıfınıza yeni işlevler ekliyorsanız, sınıfınız açık / kapalı değil ancak aşırı yüklediğiniz işlevin istemcileri vardır.

Sınıfınızda çalışan yeni işlevler ekliyorsanız, hem işlev hem de işlev istemcileriniz açık / kapalı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.