DI w bibliotece .dll

Odpowiedz Nowy wątek
2019-08-30 19:14
0

Hej, piszę dla siebie małą bibliotekę w .Net.

W zasadzie to nigdy tego wcześniej nie robiłem. Chcę mieć po prostu kawałek kodu który będę sobie wykorzystywał co jakiś czas w różnych projektach.

Biblioteka ta mi trochę już urosła. Korzysta z różnych domen, i siłą rzeczy chciałem je porozdzielać po różnych klasach i komunikować się między nimi przez interfejsy, co by mieć je ogarnięte oraz móc sobie też przetestować lub mockować łatwiej.

I jakoś niespecjalnie wydaje się to praktyczne, bo później jest zabawa z IoC projektu który z biblioteki korzysta. Zastanawiam się czy:

  • biblioteki się testuje?
  • korzysta się w nich z IoC oraz DI? tzn wewnątrz dll-a.
  • czy zamyka się kilka domen w jednej bibliotece? np. operacje na stringu + IO + WebBrowser.

Pozdrawiam,
b.

edytowany 1x, ostatnio: bakunet, 2019-08-31 02:40

Pozostało 580 znaków

2019-09-05 02:10
0
somekind napisał(a):

No właśnie o to mi chodzi, że ParamsLogger robi zbyt wiele. https://en.wikipedia.org/wiki/Single_responsibility_principle

Ok, już rozumiem. Wydawało mi się, że jeśli klasa robi to jedynie przez interfejsy serwisów, to tak naprawdę one biorą na siebie ciężar pracy. Ale wnioskuję, że tak naprawdę one powinny wykonać całą pracę? Z zapisem nie ma problemu. Ale zastanawiam się jak skonfigurować obiekt loggera jeśli nie będzie on przyjmował konfiguracji...?

Pozostało 580 znaków

2019-09-05 13:27
0
bakunet napisał(a):

Ok, już rozumiem. Wydawało mi się, że jeśli klasa robi to jedynie przez interfejsy serwisów, to tak naprawdę one biorą na siebie ciężar pracy.

No jest to możliwe, ale raczej nie w Twoim przypadku. Ale może się mylę, więc wyjaśnij - czemu masz Timer w tym ParamsLogger?

Ale zastanawiam się jak skonfigurować obiekt loggera jeśli nie będzie on przyjmował konfiguracji...?

No w tym rzecz, że powinien przyjmować konfigurację. A obecnie nie przyjmuje - konstruktor jest przeciez bezparametrowy.


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."

Pozostało 580 znaków

2019-09-06 05:22
0
somekind napisał(a):

(...)
No w tym rzecz, że powinien przyjmować konfigurację. A obecnie nie przyjmuje - konstruktor jest przeciez bezparametrowy.

Próbuję zrozumieć co dokładnie masz na myśli. Choć wydaje mi się, że powoli zaczynam kumać. Wcześniej ponownie wpadłem w swoją pułapkę, i idąc na łatwiznę skorzystałem z IoC rejestrując mój logger jako singleton. Teraz w każdej klasie próbuję utworzyć instancję na zasadzie:

private static readonly IParamsLogger _log = new ParamsLogger();

I tu zaczynają się schody. Wydaje mi się, że albo ponownie będę musiał gdzieś utworzyć singleton, albo utworzyć kolekcję loggerów, gdzie każdy kolejny będzie dodawany. Jeszcze nie wiem jak to ogarnąć, ale coś wymyślę. Inaczej skończę z n ilością instancji.

Jak chodzi o konfigurację samego loggera, to wydaje mi się, że będzie mógł być tworzony przy wykorzystaniu info ze stosu, więc nie muszę przyjmować nic w konstruktorze. Jak wspominałem wcześniej, pozostaje mi jedynie kwestia utworzenia jednego obiektu zamiast tuzina takich samych. A singleton lub kolekcja będą zasysać info z pliku konfiguracyjnego.

O to Ci chodziło, jestem blisko?

Pozostało 580 znaków

2019-09-06 13:51
0
somekind napisał(a):

No właśnie o to mi chodzi, że ParamsLogger robi zbyt wiele. https://en.wikipedia.org/wiki/Single_responsibility_principle

W dzisiejszym odcinku Ulicy Sezamkowej się nauczyłem jak utworzyć singleton oraz wzorca fabryki. W fabryce ładuję konfigurację i przekazuję ją do właściwej klasy loggera. Nie wiem czy nie przekombinowałem trochę z tą własnością. Ale działa, lockuje się na wypadek kilku wątków, więc powinno być spoko. Też później będę chciał jeszcze spojrzeć świeżym okiem na połączenie fabryki + fasady.

Będę wdzięczny za wszelkie uwagi.

Pozostało 580 znaków

2019-09-06 14:38
0
bakunet napisał(a):

I tu zaczynają się schody. Wydaje mi się, że albo ponownie będę musiał gdzieś utworzyć singleton, albo utworzyć kolekcję loggerów, gdzie każdy kolejny będzie dodawany. Jeszcze nie wiem jak to ogarnąć, ale coś wymyślę. Inaczej skończę z n ilością instancji.

Ale co w tym złego? Czemu Ci zależy na singletonie?

Jak chodzi o konfigurację samego loggera, to wydaje mi się, że będzie mógł być tworzony przy wykorzystaniu info ze stosu, więc nie muszę przyjmować nic w konstruktorze. Jak wspominałem wcześniej, pozostaje mi jedynie kwestia utworzenia jednego obiektu zamiast tuzina takich samych. A singleton lub kolekcja będą zasysać info z pliku konfiguracyjnego.

Jeśli masz obiekt z normalnym konsturktorem, w którym wstrzykujesz zależności, np. ParamsLogger(IFileService, IStringService), to w testach możesz utworzyć mocki, a w normalnym kodzie możesz mieć jakąś fabryczkę, która wczytuje konfiguracje z pliku, tworzy odpowiednie FileService oraz StringService, a na końcu faktyczny ParamsLogger.
Wszystko jest proste, eleganckie, testowalne, rozszerzalne i nie ma niespodzianek typu logger, który po utworzeniu wczytuje sobie sam swoją konfigurację z jakiegoś pliku.


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."

Pozostało 580 znaków

2019-09-07 02:15
0

@somekind:

Chcę mieć singleton, żeby mieć kontrolę nad zapisem logów do jednego pliku.

Co do fabryki to wydaje mi się że faktycznie może ona istnieć bez fasady. Popróbuję zaraz na prostych przykładach żeby ją lepiej zrozumieć i umieć wykorzystać w tym projekcie.

Pozostało 580 znaków

2019-09-07 15:14
0

@somekind:

Poniżej mam uproszczony kod. Na razie udało mi się zrobić coś na zasadzie jak niżej. Chcę uniknąć wstrzykiwania zależności w konstruktor ObjectService, w przeciwnym wypadku IoC kontener aplikacji będzie chciał rozwiązać zależności. A nie chcę żeby projekt aplikacji wiedział o zależnościach biblioteki. Zastanawiam się jak rozwiązać problem podmieniania fabryki przy testowaniu. Więc stworzyłem własność Factory, która w teście jest podmieniana makietą:

public class ObjectService : IObjectService
        {
            public ObjectService()
            {
                Factory = new ObjectFactory();
            }

            public IObjectFactory Factory { get; set; }

            public IObjectModel GetObject(string firstName)
            {
                return Factory.GetObject(firstName);
            }
        }

Więc w teście jednostkowym wykorzystuję _factoryMock

public class ObjectServiceTests
        {
            private readonly ObjectService _serv;
            private readonly Mock<IObjectFactory> _factoryMock;
            private readonly Mock<ISomeService> _someServMock;
            private readonly string _someFirstName = "SomeFirstName";

            public ObjectServiceTests()
            {
                _someServMock = new Mock<ISomeService>();
                _someServMock.SetupGet(s => s.SecondName).Returns("Cos");

                _factoryMock = new Mock<IObjectFactory>();
                _factoryMock.Setup(f => f.GetObject(_someFirstName))
                    .Returns(new ObjectModel(_someFirstName, _someServMock.Object));

                _serv = new ObjectService();
            }

            [Fact]
            public void GetObject_Called_ReturnsObject()
            {
                _serv.Factory = _factoryMock.Object;

                IObjectModel newObj = _serv.GetObject(_someFirstName);

                Assert.Equal(_someFirstName + ", Cos", newObj.FullName);
            }
        }

Zastanawiam się czy wykorzystanie public IObjectFactory Factory { get; set; } jest poprawne? Na razie nie mam lepszego pomysłu.

EDIT właśnie wyczytałem, że to jest forma property DI. Chyba przy niej zostanę, jako że zaspokaja moje oczekiwania.

edytowany 3x, ostatnio: bakunet, 2019-09-07 16:44

Pozostało 580 znaków

2019-09-07 17:21
0

Ok, chyba dopiąłem temat:

Choć w fabryce mogłem interfejsy z tej metody wczytywać do Loggera inaczej, ale to już zostawiam na przyszłość TODO

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0