2012-02-01 10 views
7

Why You Should Be Using Interfaces numaralı yazara ait Nick Hodges bloguyla okudum ve kodlamada daha yüksek bir düzeyde arabirimlere zaten aşık olduğum için, bunu nasıl genişletebileceğime bakmaya karar verdim Düşük seviyeler ve VCL sınıflarında bunun için hangi desteğin var olduğunu araştırmak.TStrings ve TStringList ile bir arabirime karşı kod

var 
    MyList : TStrings; 
    sCommaText : string; 
begin 
    MyList := TStringList.Create; 
    try 
    MyList.LoadFromFile('c:\temp\somefile.txt'); 
    sCommaText := MyList.CommaText; 

    // ... do something with sCommaText..... 

    finally 
    MyList.Free; 
    end; 
end; 

Güzel bir basitleştirme eğer görünüyor: ihtiyacım

Yaygın bir yapı virgül metin dizesine küçük bir metin dosyası listesini yüklemek için bu kod örneğin bir TStringList ile basit bir şey yapmaktır Ben bir arayüz olarak MyList kullanarak yazabiliriz - bu deneme-nihayet ve geliştirmek okunabilirliği kurtulmak olacaktır:

var 
    MyList : IStrings; 
     //^^^^^^^ 
    sCommaText : string; 
begin 
    MyList := TStringList.Create; 
    MyList.LoadFromFile('c:\temp\somefile.txt'); 
    sCommaText := MyList.CommaText; 

    // ... do something with sCommaText..... 

end; 

bir IStrings olsa tanımlanmış göremiyorum - kesinlikle Classes.pas içinde, olmasına rağmen OLE programlama ile bağlantılı olarak referanslar internet üzerinden. Var mı? Bu geçerli bir basitleştirme mi? Delphi XE2 kullanıyorum.

+4

Benim düşüncemi istiyorsan: yapma! Arayüzleri asla kullanmamanın bir çözümü olmadığı gibi, her şey için arayüzler de kullanılmaz. Hatta Nick bile TStrings/TStringList'in son blog yazısında sınıf örnekleri olarak kullanılmasını istiyor. –

+4

TStrings, 'neredeyse' bir arabirimdir, farklı uygulamalara sahip olabilecek soyut bir sınıftır. Mümkün olduğunda, TStringList yerine sadece TStrings'i parametre tipi olarak geçiriyorum. – mjn

+0

@UweRaabe ile aynı fikirdeyim. Arayüzler güçlüdür ve güçlü araçlar sıklıkla yeni başlayanlar tarafından kötüye kullanılmaktadır. Sadece bir nesne referansı yerine bir arayüz referansı kullanmayın, çünkü bu mümkün. Geniş açılabilir tasarıma - arayüzlerin orijinal amacına bağlı kalmanızı tavsiye ederim. – kludg

cevap

6

RTL/VCL'de ne istediğinizi yapan hiçbir arabirim yok (aynı arabirimi TStrings ile ortaya çıkarın). Eğer böyle bir şeyi kullanmak istiyorsan, kendin icat etmelisin.

Böyle bir sargı ile bunu uygulamaya olacaktır:

type 
    IStrings = interface 
    function Add(const S: string): Integer; 
    end; 

    TIStrings = class(TInterfacedObject, IStrings) 
    private 
    FStrings: TStrings; 
    public 
    constructor Create(Strings: TStrings); 
    destructor Destroy; override; 
    function Add(const S: string): Integer; 
    end; 

constructor TIStrings.Create(Strings: TStrings); 
begin 
    inherited Create; 
    FStrings := Strings; 
end; 

destructor TIStrings.Destroy; 
begin 
    FStrings.Free; // don't use FreeAndNil because Nick might see this code ;-) 
    inherited; 
end; 

function TIStrings.Add(const S: string): Integer; 
begin 
    Result := FStrings.Add(S); 
end; 

Doğal gerçek sınıfta TStrings arayüzünün kalanını tamamlayacağını. Böyle bir sarmalayıcı sınıfı ile yapın, böylece bir örneğine erişim sağlayarak her tür TStrings'u sarabilirsiniz.

böyle kullanın:

var 
    MyList : IStrings; 
.... 
MyList := TIStrings.Create(TStringList.Create); 

Aslında TIStrings.Create arayarak kirli işlerini yapmak için bir yardımcı işlev eklemek tercih edebilirsiniz.

Ayrıca, ömür boyu bir sorun olabileceğini unutmayın. Temelindeki TStrings örneğinin ömrünün yönetimini devralmayan bu sarma aracının bir varyantını isteyebilirsiniz. Bu, TIStrings yapıcı parametresiyle düzenlenebilir.


Kendim, bunun ilginç bir düşünce deneyi olduğunu düşünüyorum, ama gerçekten mantıklı bir yaklaşım değil. TStrings sınıfı, arayüzlerin sunduğu tüm avantajlara sahip soyut bir sınıftır. Onu olduğu gibi kullanmak için gerçek bir olumsuzluk görmüyorum.

+4

Neden sadece bir TIStrings oluşturmak istemiyorsunuz: Bağlantılar olmadan erişilebilen TStrings varsayılan özellik tüm yöntemleri sarmak için? –

+1

@arnaud bu kodu çok daha karmaşık bir hale getirecektir çünkü "Dizeleri" çok yazmanız veya bir yerel mağazaya kaydetmeniz gerekir. Varsayılan özellik, yalnızca dizi özellikleri için önler. Ama tüm istediğin, gitmek için iyi bir yol olacak bir RAII öykünücüsü olsaydı "mantıklı yaklaşım" için –

+1

+1'i tahmin et!8-) Düzenlilik ve MyList.Free'nin kaybolduğu gerçeği için – mj2008

4

TStrings, soyut bir sınıf olduğundan, bir arabirim sürümü çok fazla sağlamaz. Bu arabirimin herhangi bir uygulayıcısı kesinlikle TStrings soyundan gelecektir, çünkü hiç kimse TStrings'un yaptığı her şeyi yeniden uygulamak istemez.

  1. Otomatik kaynak temizleme: Bir TStrings arayüzü isteyen iki nedene görüyoruz. Bunun için TStrings'a özel bir araca ihtiyacınız yoktur. Bunun yerine, JCL'den ISafeGuard arabirimini kullanın.İşte bir örnek:

    var 
        G: ISafeGuard; 
        MyList: TStrings; 
        sCommaText: string; 
    begin 
        MyList := TStrings(Guard(TStringList.Create, G)); 
    
        MyList.LoadFromFile('c:\temp\somefile.txt'); 
        sCommaText := MyList.CommaText; 
    
        // ... do something with sCommaText..... 
    end; 
    

    , aynı kullanım ömrüne sahiptir IMultiSafeGuard kullanmalıdır Birden çok nesne korumak için.

  2. Dış modüller ile birlikte çalışma.IStrings bunun için nedir. Delphi, mevcut TStrings soyundan GetOleStrings'u aradığınızda döndürülecek olan TStringsAdapter sınıfı ile uygular. Bir dize listeniz olduğunda kullanın ve IStrings veya IEnumString arabirimlerini bekleyen başka bir modüle erişim vermeniz gerekir. Bu arayüzler aksi taktirde kullanışsızdır - ne de TStrings'un yaptığı her şeyi sağlamamaktadır - bu nedenle yapmanız gerekmedikçe bunları kullanmayın. Birlikte çalıştığınız harici modülü garanti her zaman modülü ile derlenen aynı Delphi sürümü ile derlenmiş olacak bir şey olursa

    , o zaman çalışma zamanı paketleri kullanmalı ve doğrudan TStrings kökenini geçmesi . Paylaşılan paket, her iki modülün de sınıfın aynı tanımını kullanmasına izin verir ve bellek yönetimi büyük ölçüde basitleştirilmiştir.

+0

'ISafeGuard', jenerik ve tip güvenliği için ağlıyor. Yazmak da oldukça önemsiz. Eğer zaten JCL kullanmıyorsanız, buna ulaşmak için JCL'ye bağımlı olmaya değmezsiniz. İlgi çekici bir çözüm için –

+0

@Rob: +1. Akademik olarak büyüleyici ama iş arkadaşlarıma muhtemelen açıklanamaz! –