Wstrzyknięcie zależności za pomocą interfejsów lub klas

Byłem winny posiadania relacji 1 do 1 między moimi interfejsami i konkretnymi klasami podczas korzystania z wstrzykiwania zależności. Kiedy muszę dodać metodę do interfejsu, kończę łamanie wszystkich klas, które implementują interfejs.

Jest to prosty przykład, ale załóżmy, że muszę wstrzyknąćILogger w jedną z moich klas.

<code>public interface ILogger
{
    void Info(string message);
}

public class Logger : ILogger
{
    public void Info(string message) { }
}
</code>

Posiadanie takiej relacji 1 do 1 jest jak zapach kodu. Ponieważ mam tylko jedną implementację, czy są jakieś potencjalne problemy, jeśli utworzę klasę i zaznaczęInfo metoda jako wirtualna do zastąpienia w moich testach zamiast tworzenia interfejsu tylko dla jednej klasy?

<code>public class Logger
{
    public virtual void Info(string message)
    {
        // Log to file
    }
}
</code>

Jeśli potrzebuję innej implementacji, mogę przesłonićInfo metoda:

<code>public class SqlLogger : Logger
{
    public override void Info(string message)
    {
        // Log to SQL
    }
}
</code>

Jeśli każda z tych klas ma określone właściwości lub metody, które mogłyby stworzyć nieszczelną abstrakcję, mógłbym wyodrębnić klasę bazową:

<code>public class Logger
{
    public virtual void Info(string message)
    {
        throw new NotImplementedException();
    }
}

public class SqlLogger : Logger
{
    public override void Info(string message) { }
}

public class FileLogger : Logger
{
    public override void Info(string message) { }
}
</code>

Powodem, dla którego nie oznaczyłem klasy bazowej jako abstrakcyjnej, jest to, że jeśli kiedykolwiek chciałbym dodać inną metodę, nie złamałbym istniejących implementacji. Na przykład, jeśli mojaFileLogger potrzebne aDebug metoda, mogę zaktualizować klasę bazowąLogger bez zrywania istniejącegoSqlLogger.

<code>public class Logger
{
    public virtual void Info(string message)
    {
        throw new NotImplementedException();
    }

    public virtual void Debug(string message)
    {
        throw new NotImplementedException();
    }
}

public class SqlLogger : Logger
{
    public override void Info(string message) { }
}

public class FileLogger : Logger
{
    public override void Info(string message) { }
    public override void Debug(string message) { }
}
</code>

Ponownie jest to prosty przykład, ale kiedy powinienem preferować interfejs?

questionAnswers(4)

yourAnswerToTheQuestion