Nesneyi aynı yönteme iki kez geçirin veya birleştirilmiş arayüzle birleştirin mi?


15

Bir dijital tahta ile konuştuktan sonra bir veri dosyası oluşturan bir yöntem var:

CreateDataFile(IFileAccess boardFileAccess, IMeasurer boardMeasurer)

İşte boardFileAccessve boardMeasurerbir aynı örneği olan Boardnesne olduğunu uygular hem IFileAccessve IMeasurer. IMeasurerbu durumda basit bir ölçüm yapmak için kart üzerindeki bir pimi aktif hale getirecek tek bir yöntem için kullanılır. Bu ölçümden elde edilen veriler daha sonra kullanılarak kart üzerinde yerel olarak depolanır IFileAccess. Boardayrı bir projede yer almaktadır.

Ben CreateDataFilehızlı bir ölçüm yaparak ve daha sonra veri depolayarak bir şey yapıyor sonucuna geldim , ve her ikisini de aynı yöntemle yapmak daha sonra bir ölçüm yapmak ve bir dosyaya yazmak zorunda bu kodu kullanarak başkası için daha sezgisel ayrı yöntem çağrıları olarak.

Bana göre, aynı nesneyi iki kez bir yönteme aktarmak garip görünüyor. Yerel bir arayüz yapma kabul ettik IDataFileCreatoruzatacaktır IFileAccessve IMeasurerardından bir içeren bir uygulaması Boardsadece gerekli arayacak örneği Boardyöntemleri. Aynı tahta nesnesinin her zaman ölçüm ve dosya yazma için kullanılacağı düşünüldüğünde, aynı nesneyi bir yönteme iki kez geçirmek kötü bir uygulama mıdır? Öyleyse, yerel bir arayüz ve uygulama kullanmak uygun bir çözüm müdür?


2
Kodunuzun amacını kullandığınız adlardan çıkarmak imkansızdır. CreateDataFile adlı bir yönteme iletilen IDataFileCreator adlı bir arabirim zihin bozucu. Veriyi sürdürme sorumluluğu için rekabet ediyorlar mı? Zaten CreateDataFile yöntemi hangi sınıftır? Ölçümün kalıcı verilerle ilgisi yoktur, çok şey açıktır. Sorunuz, kodunuzla ilgili yaşadığınız en büyük sorun değil.
Martin Maat

Dosya erişim nesnenizin ve ölçüm nesnenizin iki farklı nesne olabileceği düşünülebilir mi? Evet derim. Şimdi değiştirirseniz , ağ üzerinden ölçüm almayı destekleyen sürüm 2'de geri değiştirmeniz gerekir .
user253751

2
Yine de başka bir soru - veri dosyası erişim ve ölçüm nesneleri neden ilk etapta aynı?
user253751

Yanıtlar:


40

Hayır, bu gayet iyi. Bu, yalnızca mevcut uygulamanızla ilgili olarak API'nın aşırı mühendislik yapıldığı anlamına gelir .

Ancak bu , veri kaynağının ve ölçerin farklı olduğu bir kullanım durumunun asla olmayacağını kanıtlamaz . Bir API'nin amacı, hepsi kullanılmayacak olan uygulama programcısı olanaklarını sunmaktır. Net anlaşılabilirliğin azalması için API kullanıcılarının API'yi karmaşıklaştırmadıkça yapabileceklerini yapay olarak kısıtlamamalısınız.


7

İle Anlaştı KilianFoth cevabı @ bu mükemmel para cezası olduğunu.

Yine de, isterseniz, her iki arabirimi de uygulayan tek bir nesneyi alan bir yöntem oluşturabilirsiniz:

public object CreateDataFile<T_BoardInterface>(
             T_BoardInterface boardInterface
    )
    where T_BoardInterface : IFileAccess, IMeasurer
{
    return CreateDataFile(
                boardInterface
            ,   boardInterface
        );
}

Bağımsız değişkenlerin farklı nesneler olması gerektiğine dair genel bir neden yoktur ve eğer bir yöntem bağımsız değişkenlerin farklı olmasını gerektiriyorsa, sözleşmesinin açıkça belirtmesi gereken özel bir gerekliliktir.


4

Ben CreateDataFilehızlı bir ölçüm yaparak ve daha sonra veri depolayarak bir şey yapıyor sonucuna geldim , ve her ikisini de aynı yöntemle yapmak daha sonra bir ölçüm yapmak ve bir dosyaya yazmak zorunda bu kodu kullanarak başkası için daha sezgisel ayrı yöntem çağrıları olarak.

Bence bu senin sorunun. Yöntem olduğu değil bir şey yapıyor. Her ikisi de diğer nesnelere yüklenen farklı cihazlara G / Ç içeren iki ayrı işlem gerçekleştirir :

  • Bir ölçüm getir
  • Bu sonucu bir yere bir dosyaya kaydedin

Bunlar iki farklı G / Ç işlemi. Özellikle, ilki dosya sistemini hiçbir şekilde değiştirmez.

Aslında, zımni bir orta adım olduğunu not etmeliyiz:

  • Bir ölçüm getir
  • Ölçümü bilinen bir biçime seri hale getirme
  • Serileştirilmiş ölçümü bir dosyaya kaydedin

API'nız bunların her birini ayrı bir biçimde sağlamalıdır. Arayanın herhangi bir yerde saklamadan ölçüm yapmak istemeyeceğini nasıl anlarsınız? Başka bir kaynaktan ölçüm almak istemediklerini nereden biliyorsunuz? Cihazdan başka bir yerde saklamak istemediklerini nereden biliyorsunuz? Operasyonları ayırmak için iyi bir neden var. Bir anda çıplak minimum her oyuncağı olmalı kullanılabilir herhangi arayana. Kullanım durumum bunu çağırmazsa, bir dosyaya ölçüm yazmak zorunda kalmamalıyım.

Örnek olarak, bunun gibi işlemleri ayırabilirsiniz.

IMeasurer ölçümü getirmenin bir yolu vardır:

public interface IMeasurer
{
    IMeasurement Measure(int someInput);
}

Ölçüm türünüz sadece stringveya gibi basit bir şey olabilir decimal. Bunun için bir arayüze veya sınıfa ihtiyacınız olduğu konusunda ısrar etmiyorum, ancak buradaki örneği daha genel hale getiriyor.

IFileAccess dosyaları kaydetmek için bazı yöntemler vardır:

interface IFileAccess
{
    void SaveFile(string fileContents);
}

Sonra bir ölçümü seri hale getirmenin bir yoluna ihtiyacınız var. Bunu bir ölçümü temsil eden sınıfa veya arayüze yerleştirin veya bir yardımcı yöntem kullanın:

interface IMeasurement
{
    // As part of the type
    string Serialize();
}

// Utility method. Makes more sense if the measurement is not a custom type.
public static string SerializeMeasurement(IMeasurement m)
{
    return ...
}

Bu serileştirme işleminin henüz ayrılmış olup olmadığı açık değildir.

Bu tür bir ayırma API'nizi geliştirir. Arayanın , G / Ç işlemlerini gerçekleştirmek için önceden tasarlanmış fikirlerinizi zorlamak yerine neye ve ne zaman karar vermesini sağlar . Arayanlar , yararlı olup olmadığını düşünün, geçerli herhangi bir işlemi gerçekleştirmek için kontrole sahip olmalıdır .

Her işlem için ayrı uygulamalarınız olduğunda, CreateDataFileyönteminiz yalnızca

fileAccess.SaveFile(SerializeMeasurement(measurer.Measure()));

Özellikle, tüm bunları yaptıktan sonra yönteminiz çok az değer katıyor. Yukarıdaki kod satırı, arayanlarınızın doğrudan kullanması zor değildir ve yönteminiz en fazla kolaylık sağlamak içindir. O olmalı ve isteğe bağlı bir şeydir . Bu, API'nin davranışı için doğru yoldur.


İlgili tüm bölümler hesaba katıldığında ve yöntemin sadece bir kolaylık olduğunu kabul ettikten sonra, sorunuzu yeniden yazmamız gerekir:

Arayanlarınız için en yaygın kullanım durumu hangisidir?

Tüm mesele, aynı tahtadan ölçüm yapmak ve aynı tahtaya yazmak için tipik kullanım durumunu biraz daha uygun hale getirmekse, Boarddoğrudan sınıfta kullanılabilir hale getirmek mükemmel bir mantıklıdır :

public class Board : IMeasurer, IFileAccess
{
    // Interface methods...

    /// <summary>
    /// Convenience method to measure and immediate record measurement in
    /// default location.
    /// </summary>
    public void ReadAndSaveMeasurement()
    {
        this.SaveFile(SerializeMeasurement(this.Measure()));
    }
}

Bu kolaylık sağlamazsa, yöntemle hiç uğraşmazdım.


Bu bir kolaylık yöntemi olmak başka bir soruyu da beraberinde getiriyor.

Meli IFileAccessarayüz ölçüm türü ve nasıl serialize biliyor mu? Öyleyse, aşağıdakilere bir yöntem ekleyebilirsiniz IFileAccess:

interface IFileAccess
{
    void SaveFile(string fileContents);
    void SaveMeasurement(IMeasurement m);
}

Şimdi arayanlar bunu yapar:

fileAccess.SaveFile(measurer.Measure());

bu da soruda tasarlandığı kadar kolaylık yönteminizden daha kısa ve muhtemelen daha açıktır.


2

Tüketici müşteri, tek bir kalem yeterli olduğunda bir çift kalemle uğraşmak zorunda kalmamalıdır. Sizin durumunuzda, çağrılıncaya kadar neredeyse yoklar CreateDataFile.

Önereceğiniz potansiyel çözüm, birleştirilmiş türetilmiş arayüz oluşturmaktır. Bununla birlikte, bu yaklaşım, her iki arabirimi de uygulayan tek bir nesne gerektirir, bu da oldukça kısıtlayıcıdır, tartışmalı bir şekilde temelde belirli bir uygulamaya göre özelleştirilmesinden dolayı sızdıran bir soyutlamadır. Birisi iki arabirimi ayrı nesnelerde uygulamak isterse ne kadar karmaşık olacağını düşünün: diğer nesneyi iletmek için arabirimlerin birindeki tüm yöntemleri proxy yapmak zorunda kalacaklardı. (FWIW, başka bir seçenek, bir nesnenin türetilmiş bir arabirim aracılığıyla iki arabirim uygulamak zorunda kalması yerine arabirimleri birleştirmek.)

Bununla birlikte, uygulama üzerinde daha az kısıtlayıcı olan / uygulama için daha az kısıtlayıcı olan başka bir yaklaşım, IFileAccessbir IMeasurerbileşim içinde eşleştirilmesidir , böylece bunlardan biri diğerine bağlı ve diğerine referans verir. (Bu, şimdi de eşleşmeyi temsil ettiğinden, bunlardan birinin soyutlamasını biraz arttırır.) Sonra CreateDataFile, referanslardan sadece birini alabilir IFileAccessve gerekirse diğerini elde edebilir. Bir nesne olarak Geçerli uygulama olduğunu uygular hem arayüzler olur basitçe return this;kompozisyon başvuru için, burada alıcı IMeasureriçinde IFileAccess.

Eşleştirme, geliştirme işleminin bir noktasında yanlış çıkarsa, yani aynı dosya erişimiyle bazen farklı bir ölçüm cihazı kullanılırsa, bu aynı eşleştirmeyi ancak bunun yerine daha yüksek bir seviyede yapabilirsiniz, yani eklenen ek arayüz türetilmiş bir arayüz değil, bir dosya erişimi ve ölçücüyü türetme yerine kompozisyonla eşleştiren iki alıcıya sahip bir arayüzdür. Tüketici müşteri daha sonra eşleştirme devam ettiği sürece kendilerini ilgilendirecek bir maddeye ve gerektiğinde (yeni eşleşmeler oluşturmak için) ele alınacak bireysel nesnelere sahiptir.


Başka bir notta, kimin sahibi olduğunu sorabilirim CreateDataFileve soru bu üçüncü tarafın kim olduğu ile ilgilidir. Zaten çağrıştıran CreateDataFile, sahip olan nesnenin / sınıfının CreateDataFileve IFileAccessve IMeasurer. Bazen bağlam hakkında daha geniş bir görüş aldığımızda, alternatif, bazen daha iyi organizasyonlar ortaya çıkabilir. Bağlam eksik olduğu için burada yapmak zor, bu yüzden sadece düşünce için yiyecek.


0

Bazıları CreateDataFileçok fazla şey yaptığını ortaya çıkardı . Bunun yerine Boardçok fazla şey yaptığını önerebilirim , çünkü bir dosyaya erişim kurulun geri kalanından ayrı bir endişe gibi görünüyor.

Ancak, bunun bir hata olmadığını varsayarsak, daha büyük sorun arayüzün istemci tarafından tanımlanması gerektiğidir CreateDataFile.

Arayüz Ayrışma İlkesi istemci ihtiyacı olandan bir arayüzün daha bağlıdır zorunda olmaması gerektiğini belirtmektedir. İfadeyi bu diğer cevaptan ödünç alarak , bu "müşterinin ihtiyaç duyduğu bir arayüz tarafından tanımlanır" şeklinde ifade edilebilir.

Şimdi, bu istemciye özgü arabirimi IFileAccessve IMeasurerdiğer yanıtların önerdiği gibi oluşturmak mümkündür , ancak sonuçta bu istemcinin kendisi için özel olarak hazırlanmış bir arabirimi olmalıdır.


@Downvoter - Peki ya yanlış ya da geliştirilebilir?
Xtros
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.