Nasıl yukarı yeni nesnelere DI kullanırken

oy
1

Ben sadece benim için birkaç şey temizlenmiş Pluralsight üzerinde Bağımlılık Enjeksiyon kursu izliyordum. Ama birkaç katmandan üzerine çıkması olmasına rağmen, tam olarak ne zaman gitmek edebileceğinizi hiçbir bilgi de yoktu sadece codde kadar yeni nesnelere sahip .

Bu benim kavramak mücadele ediyorum bulmacanın son parçası. Ben Compisition Root hakkında bilmek ve kabaca nasıl kullanılacağını. Ben ServiceLocator önlemek için de ben de çalıştığım bir şirkette yanyana gördük ki (kod tabanında hemen her sınıfta bir ctor parametresi olarak tanımlayarak tüm kod seviyeleri ile IoC kapsayıcı aşağı geçen önlemek için biliyorum için).

en Bence her şeyde eline imkansız kullanışsız olduğuna inanıyoruz yerin altındaki iki örneğe bakalım.

Ben bağımlılıkları enjekte edebilir, ancak sorun dinamik bir döngü içinde Doee nesneleri oluşturmak için nasıl yüzden muhtemelen, hepsinden sonra Nesne Enjeksiyon çağrılmaz, her şeyi enjekte edemez:

public class MyClass
{
    private IVerifyer _verifyer;
    public MyClass(IVerifyer verifyer)
    {
        _verifyer = verifyer;
    }

    public IList<Doer> PrepareDoingSomething(IList<IDoees> doees)
    {
        var doers = new List<Doer>();
        foreach (var doee in doees)
        {
            if (!Verifyer.Verify(doee)) throw new Exception(Blablabla...);
            doers.Add(new Doer(doee));
        }
        return doers;
    }
}

Şimdi bazı daha az dinamik durumlarda, sorun bazı IO sınıfları için orada bir arayüz ne de deney kodunda ile zor anlaşma demektir kullanılabilir soyut bir taban sınıfı, ne olduğunu ve aynı zamanda ben bile nasıl bilemeyiz ki Süreç sınıf gibi bir IoC konteyner, onları işlemek için:

public class Processor
{
    public Process ProcessSomething(IProcessee processee)
    {
        // do some pre-processing stuff here
        // static Start() returns a new Process instance
        return Process.Start(C:\MyApp.exe, $-option {processee.Option1});
    }
}

Şimdiye kadar ne yaptık her iki durumda da ben enjekte soyut bir fabrika sınıf uygulamasına ve bu (bir döngüde yani dinamik) ihtiyacınız olduğunda ihtiyacım olanı bana verir. Ben üretim amaçlı bir uygulama var. Test kodunda bunu uygulamak ya da (o soyut olduğundan) sadece alay ya. Süreç sınıf için ben gerçek Süreç sınıfına aramalar geçer arayüzü (I) ProcessProxy ile bir proxy sınıf sunduk. Ben de kolayca ben gerekirse o alay edebilir. iki örnek daha sonra aşağıda listelenen kadarıyla dönüşür.

Benim sorum, doğru yolu (benim ana kaygıları vardır) bu iki durumda da gitmek bu? Ben inatçı cevapları tetikleyebilir biliyorum, ama sadece o temiz ve yalındır ders kitabı benzeri DependencyInjection ve CompositionRoot uygulanması ruhuyla önerilen yolu olup olmadığını anlamaya çalışıyorum. O gitmek için tercih edilen yöntem değilse, o zaman bu nedir?

Döngü örneği üstlenmeden sonra ve DI etkin:

public class MyClass
{
    private IVerifyer _verifyer;
    private AbstractDoerFactory _doerFactory;
    public MyClass(IVerifyer verifyer, AbstractDoerFactory doerFactory)
    {
        _verifyer = verifyer;
        _doerFactory = doerFactory;
    }

    public IList<Doer> PrepareDoingSomething(IList<IDoees> doees)
    {
        var doers = new List<Doer>();
        foreach (var doee in doees)
        {
            if (!_verifyer.Verify(doee)) throw new Exception(Blablabla...);
            doers.Add(_doerFactory.GetNewDoer(doee));
        }
        return doers;
    }
}

Süreç örnek üstlenmeden sonra ve DI etkin:

public interface IProcessProxy : IDisposable
{
    TextReader StandardOutput { get; }
    TextReader StandardError { get; }
    int ExitCode { get; }
    Start(string fileName, string arguments);
    void Kill();
}

public class Processor
{
    private AbstractProcessProxyFactory _processProxyFactory;
    public Processor(AbstractProcessProxyFactory processProxyFactory)
    {
        _processProxyFactory = processProxyFactory;
    }

    public IProcessProxy ProcessSomething(IProcessee processee)
    {
        // do some pre-processing stuff here
        var processProxy = _processProxyFactory.GetProxyFactory();
        return processProxy.Start(C:\MyApp.exe, $-option {processee.Option1});
    }
}
Oluştur 20/10/2018 saat 13:58
kaynak kullanıcı
Diğer dillerde...                            


2 cevaplar

oy
1

DependencyInjection karmaşık polimorfik uygulamaları düzenlemek için inanılmaz güçlü bir araçtır. imkanları kullanmak için hep bakmak - ama Başvurunuzun her detayını işlemek için ideal değil.

Sadece örnek amaçlı olabilir rağmen özel bir işlem sınıfı ile takas etmek isteyen için çok iyi bir nedeni vardı sürece, ben genelde System.Process gibi standart bir sistem hizmeti üzerine sizin bağımlılığını kaldırmak için DI kullanmak düşünmek olmaz . Bu Bağımlılık Injection overusing bir durum olurdu.

Bu, dinamik olarak da bir fabrika oldukça yararlı olduğu bulunmuştur önyükleme işlemi sonrasında türleri örneklerini oluşturmak için gerekli olan zaman, söz konusu. En büyük esneklik için tek bir fabrika örneği güvenmeyin. Bunun yerine, bağımsız farklı türleri için fabrikalar kayıt olanağı sağlar.

public interface IFactory
{ 
    Type FactoryType;
    object CreateInstance(); 
}

namespace Generic {
    public interface IFactory<T> : IFactory
    {
        new T CreateInstance();
    }
}

public class DoThisFactory : IFactory<DoThis> { ... }
public class DoThatFactory : IFactory<DoThat> { ... }


public class MyClass
{
    // use property injection
    public DoThisFactory DoThisFactory { get; set; }       
    public DoThatFactory DoThatFactory { get; set; }

    private DoThis _doThis = null;
    private DoThat _doThat = null;

    public DoThis DoThis
    {
        get {
            if(_doThis == null) _doThis = DoThisFactory.CreateInstance();
            return _doThis;
        }
    }

    public DoThat DoThat
    {
        get {
            if(_doThat == null) _doThat = DoThatFactory.CreateInstance();
            return _doThat;
        }
    }
}

bağımlılıklar açık olan - Yukarıda, Sınıfım Tek yapması gereken şeylerin farklı türde bilir. Bu bana IDoees farklı türlerine farklı (veya aynı) fabrika sınıfı sağlamamıza olanak tanır.

Eğer sonuçta çalışıyor olacağız belirli uygulama türlerini bilmiyorsanız, o zaman IFactory örnekleri dizisi enjekte ve daha sonra arama için bir Dictionary bunları kayıt etme FactoryType özelliğini kullanmanız gerekecektir.

public class MyClass
{
    private Dictionary<Type, IFactory> _registerations = new Dictionary<Type, IFactory>();

    public MyClass(IFactory[] factories)
    {
        for(int i = 0; i < factories.Count -1; i++)
        {
            _registrations.Add(factories(i).FactoryType, factories);
        }
    }

    public IEnumeruable<IDoer> GetDoers(Type[] types)
    {
        List<IDoer> doers = new List<IDoer>();
        for(int i = 0; i < types.Count - 1; i++)
        {
            doers.Add(_registerations(types(i)).CreateInstance());
        }
        return doers;
    }
}
Cevap 21/10/2018 saat 12:08
kaynak kullanıcı

oy
0

Yapmanız gerekir sorusu olmasına rağmen, OP belirtilen Sen, bir fabrika ile ilk sorunu ele alabilir. OP bakıldığında, ne olduğu belli değil IDoees, ama genellikle, yöntem argümanlar olarak iletilen ya da dönüş değeri olarak döndürülen nesneler, olma eğilimi newables ziyade enjektabl . Sorusu bile bir fabrika enjekte edip, daha sonra vardır. Bu sadece daha uygun olabilir newyukarı Doerda OP gösterildiği gibi,.

O gibi bir şey söz konusu olduğunda Processsen ise edebilir teknik olarak somut bir sınıftan bir arabirim ayıklamak ve ardından bir hale Adaptörü , bu genellikle Bağımlılık Ekleme özelliğini kullanmak için en iyi yol değildir.

Göre Bağımlılık Inversion İlke , soyutlamalar ayrıntılarına bağlı olmamalıdır; ayrıntıları soyutlamaların bağlı olmalıdır. Ne bu normalde anlamı müşterilerine ihtiyaç duydukları soyutlama tanımlamalıdır ve sonra uygulamalar bu soyutlama eşleşmesi gerektiğidir.

Bir istemci yerine diyoruz yerine, bir süreci çalıştırmak için varsa Yani, RunProcessbu adresleri probleme göre adlandırın. Örneğin, adlı bir programı çalıştırmak isterseniz encode.exe, örneğin bu amaca uygun olarak bağımlılık, modeli bazı ses dosyalarını kodlamak için:

public class Foo
{
    private readonly IEncoder encoder;

    public Foo(IEncoder encoder)
    {
        this.encoder = encoder;
    }

    public Bar DoSomething(Baz baz)
    {
        // Maybe do something else first...

        this.encoder.Encode(/*...*/);

        // Maybe do something else after...
    }
}

Daha sonra uygulayabilirsiniz IEncoderkullanarak Processeğer gerekiyorsa, API:

public class Encoder : IEncoder
{
    public void Encode(/*...*/)
    {
        // Start encode.exe here...
    }
}

Operasyon uzun koşu ise, bir dönebilirsiniz Taskgelen Encode, yerine void; Görevi iptal edebilmek için gerekirse, bir geçiş CancellationTokeniçin bir yöntem argüman olarak Encodeyöntemle; ve bunun gibi. İstemci (ler) değil, uygulama ayrıntıları gereklilikleri arasında bağımlılığını Model.

Cevap 01/11/2018 saat 07:21
kaynak kullanıcı

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more