Küçük fonksiyonlar ve bağımlı fonksiyonların aynı fonksiyonda tutulması


15

Bir dizi düğüm ayarlar ve bunları grafik benzeri bir yapıda birbirine bağlayan bir sınıf var. En iyisi:

  1. Düğümleri tek bir işlevde başlatma ve bağlama işlevini koruma
  2. Başlatma ve bağlantı işlevlerini iki farklı işlevde bulundurun (ve işlevlerin çağrılması için bağımlı bir sıraya sahip olun - ancak bu işlevlerin özel olduğunu unutmayın.)

Yöntem 1: (Bir işlevin iki şey yapması kötü, AMA bağımlı işlevselliği bir arada gruplanmış tutar - düğümler ilk olarak başlatılmadan asla bağlanmamalıdır.)

init() {
    setupNodes()
}

private func setupNodes() {
    // 1. Create array of nodes
    // 2. Go through array, connecting each node to its neighbors 
    //    according to some predefined constants
}

Yöntem 2: (Kendini belgeleme açısından daha iyi, BUT connectNodes () asla setupNodes () öğesinden önce çağrılmamalı, bu nedenle sınıf iç bileşenleriyle çalışan herkesin bu sipariş hakkında bilgi sahibi olması gerekir.)

init() {
    setupNodes()
}

private func setupNodes() {
    createNodes()
    connectNodes()
}

private func createNodes() {
    // 1. Create array of nodes
}

private func connectNodes() {
    // 2. Go through array, connecting each node to its neighbors 
    //    according to some predefined constants
}

Herhangi bir düşünceyi duymak heyecanlı.



Bunu yalnızca son nesneleri oluşturmak için kullanılabilen ara nesneleri tanımlayarak çözmenin bir yolu. Bu her zaman doğru çözüm değildir, ancak arabirim kullanıcısının bir ara durumu bir şekilde manipüle etmesi gerekiyorsa yararlıdır.
Joel Cornett

Yanıtlar:


23

Karşılaştığınız soruna geçici bağlantı denir

Bu kodun ne kadar anlaşılır olduğu konusunda endişe etme hakkınız var:

private func setupNodes() {
    createNodes();
    connectNodes();
}

Orada neler olduğunu tahmin edebilirim ama bunun başka neler olup bittiğini biraz daha netleştirdiğini söyleyebilirim:

private func setupNodes() {
    self.nodes = connectNodes( createNodes() );
}

Bu, örnek değişkenlerini değiştirmeye daha az bağlı olma avantajına sahiptir, ancak bana okunabilir olmak bir numaradır.

Bu connectNodes(), düğümlere bağımlılığını açık hale getirir .


1
Bağlantı için teşekkürler. İşlevlerim özel ve Swift'teki yapıcı - init () 'den çağrıldığından, kodumun bağladığınız örnekler kadar kötü olacağını düşünmüyorum (harici bir istemcinin bir örneği null örnek değişkeni), ancak benzer bir kokum var.
mcfroob

1
Eklediğiniz kod daha okunabilir, bu yüzden bu tarzda refactor edeceğim.
mcfroob

10

İki nedenden dolayı ayrı işlevler :

1. Özel işlevler tam da bu durum için özeldir.

Sizin initişlevi herkese açıktır ve bu arayüz, davranış, ve dönüş değeri korumak ve değiştirme hakkında endişe gereken budur. Bu yöntemden beklediğiniz sonuç, hangi uygulamayı kullanırsanız kullanın aynı olacaktır.

İşlevselliğin geri kalanı bu özel anahtar kelimenin arkasına gizlendiğinden, istediğiniz gibi uygulanabilir ... bu yüzden bir parça ilk olarak diğerine bağlı olsa bile, hoş ve modüler hale getirebilirsiniz.

2. Düğümleri birbirine bağlamak özel bir işlev olmayabilir

Bir noktada diziye başka düğümler eklemek isterseniz ne olur? Şu anda sahip olduğunuz kurulumu yok ediyor ve tamamen yeniden başlatıyor musunuz? Yoksa varolan diziye düğümler ekleyip connectNodestekrar çalıştırıyor musunuz?

Muhtemelen connectNodeshenüz oluşturulmadı düğüm dizisi (bir istisna? Durumunuza için en iyisinin ne karar vermek zorunda? Boş bir dizi döndürür) eğer aklı başında bir yanıt olabilir.


1 ile aynı şekilde düşünüyordum ve eğer düğümler başlatılmamışsa bir istisna ya da bir şey fırlatabilirim, ama özellikle sezgisel değil. Yanıtınız için teşekkürler.
mcfroob

4

Ayrıca (bu görevlerin her birinin ne kadar karmaşık olduğuna bağlı olarak), bunun başka bir sınıfı ayırmak için iyi bir dikiş olduğunu görebilirsiniz.

(Swift'in bu şekilde çalışıp çalışmadığından emin değilim, sahte kod :)

class YourClass {
    init(generator: NodesGenerator) {
        self.nodes = connectNodes(generator.make())
    }
    private func connectNodes() {

    }
}

class NodesGenerator {
    public func make() {
        // Return some nodes from storage or make new ones
    }
}

Bu, sınıfları ayırmak için düğüm oluşturma ve değiştirme sorumluluklarını ayırır: NodeGeneratoryalnızca düğümleri oluşturma / alma ile YourClassilgilenirken , yalnızca verilen düğümleri bağlama ile ilgilenir.


2

Bunun, özel yöntemlerin tam amacı olmasına ek olarak, Swift size iç işlevleri kullanma yeteneği verir.

İç yöntemler, yalnızca tek bir çağrı sitesine sahip olan işlevler için mükemmeldir, ancak ayrı özel işlevler olarak haklı hissetmediklerini düşünürler.

Örneğin, ön koşulları kontrol eden, bazı parametreleri ayarlayan ve işi yapan özel bir özyinelemeli işleve delege veren genel özyinelemeli "giriş" işlevine sahip olmak çok yaygındır.

İşte bu durumda nasıl görünebileceğine dair bir örnek:

init() {
    self.nodes = setupNodes()

    func setupNodes() {
        var nodes = createNodes()
        connect(Nodes: nodes)
    }

    private func createNodes() -> [Node]{
        // 1. Create array of nodes
    }

    func connect(Nodes: [Node]) {
        // 2. Go through array, connecting each node to its neighbors 
        //    according to some predefined constants
    }
}

Paylaşılan bir durumu mutasyona uğratmak yerine, veriyi iletmek için dönüş değerlerini ve parametrelerini nasıl kullandığımıza dikkat edin. Bu, veri akışını uygulamaya atlamaya gerek kalmadan ilk bakışta çok daha belirgin hale getirir.


0

Bildirdiğiniz her işlev, programın diğer bölümleri tarafından kullanılabilmesi için belge ekleme ve genelleme yapma yükünü de beraberinde getirir. Ayrıca, dosyadaki diğer işlevlerin kodu okuyan biri için onu nasıl kullanabileceğini anlama yükünü de taşır.

Bununla birlikte, programınızın diğer bölümleri tarafından kullanılmazsa, ayrı bir işlev olarak göstermem.

Diliniz destekliyorsa, iç içe işlevleri kullanarak yine de tek işlevli bir şey yapabilirsiniz

function setupNodes ()  {
  function createNodes ()  {...} 
  function connectNodes ()  {...}
  createNodes() 
  connectNodes() 
} 

Beyan yeri çok önemlidir ve yukarıdaki örnekte, iç fonksiyonların sadece dış fonksiyonun gövdesi içinde kullanılması gerektiği konusunda daha fazla ipucu gerekmeksizin açıktır.

Onları özel işlevler olarak tanımlasanız bile, bunların tüm dosya için hala görünür olduklarını varsayıyorum. Bu nedenle, bunları ana işlevin bildirimine yakın olarak bildirmeniz ve yalnızca dış işlev tarafından kullanılacaklarını açıklayan bazı belgeler eklemeniz gerekir.

Kesinlikle birini ya da diğerini yapmak zorunda olduğunu sanmıyorum. Yapılacak en iyi şey duruma göre değişir.

Bunu birden fazla fonksiyona bölmek, neden 3 fonksiyonun olduğunu ve hepsinin birbiriyle nasıl çalıştığını anlama yükünü ekler, ancak mantık karmaşıksa, bu ek yük karmaşık mantığın parçalanmasıyla ortaya çıkan basitlikten çok daha az olabilir. daha basit parçalara ayırın.


İlginç bir seçenek. Dediğiniz gibi, işlevin neden böyle beyan edildiğine dair biraz kafa karıştırıcı olabilir, ancak işlev bağımlılığını iyi durumda tutacağını düşünüyorum.
mcfroob

Bu sorudaki bazı belirsizlikleri cevaplamak için: 1) Evet, Swift iç fonksiyonları destekler ve 2) İki seviyeli "özel" vardır. privateyalnızca ek türü (yapı / sınıf / enum) içinde fileprivateerişime izin verirken , tüm dosya genelinde erişime izin verir
Alexander - Monica'yı yeniden eski haline
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.