Реализация принципа разделения интерфейсов для интерфейсов .NET Framework

2

Я внедряю IServiceLocator (пакет CommonServiceLocator) в свой пользовательский класс ServiceLocator.

Интерфейс имеет следующие методы для реализации:

public class CustomServiceLocator : IServiceLocator
{
    private IServiceProvider _provider;

    public RatioDissectionServiceLocator(IServiceProvider provider)
    {
        _provider = provider;
    }

    public IEnumerable<object> GetAllInstances(Type serviceType)
    {
        throw new NotImplementedException();
    }

    public IEnumerable<TService> GetAllInstances<TService>()
    {
        throw new NotImplementedException();
    }

    public object GetInstance(Type serviceType)
    {
        throw new NotImplementedException();
    }

    public object GetInstance(Type serviceType, string key)
    {
        throw new NotImplementedException();
    }

    public TService GetInstance<TService>()
    {
        return _provider.GetService<TService>();
    }
 }

Я не хочу реализовывать все методы в моем классе. Как мы можем достичь ISP для встроенных интерфейсов С#?

Любая помощь?

  • 1
    Используя свой собственный интерфейс (ы) и упаковывая встроенный интерфейс. У вас нет контроля над сторонними интерфейсами.
  • 2
    Если это не ваш интерфейс, я не думаю, что применение ISP действительно возможно.
Показать ещё 2 комментария
Теги:

1 ответ

3

Принцип разделения интерфейса гласит:

Ни один клиент не должен зависеть от методов, которые он не использует.

Это означает, что, несмотря на многие неясные и вводящие в заблуждение объяснения принципа, большой интерфейс сам по себе не нарушает принцип. Возможно, другой класс действительно зависит от всех членов интерфейса. Поэтому мы не будем смотреть на интерфейс, подобный IServiceLocator и пытаться как-то его "исправить".

Интернет-провайдер с точки зрения классов, которые зависят от интерфейсов. Если в интерфейсе 20 участников, и мой класс зависит от них всех, это не является нарушением ISP. (Это, вероятно, все виды других плохих вещей, которые не имеют ничего общего с провайдером.) Если другой класс зависит от точно такого же интерфейса и использует только несколько членов, это нарушение провайдера.

В обоих примерах это один и тот же интерфейс. Принцип не об интерфейсе. Это о том, использует ли класс, который зависит от интерфейса, все его члены.

(Другой странный пример, который я NotImplementedException вижу, - это большой интерфейс и класс, который реализует интерфейс, но выдает NotImplementedException для некоторых членов. Это также плохо, и это нарушение подстановки Лискова, но это не имеет ничего общего с ISP. Реализация интерфейс не зависит от него.)

Один из способов избежать нарушений со стороны провайдера - это написать интерфейсы с точки зрения классов, которые зависят от них. Что бы ни требовал ваш класс от его зависимости, напишите свой интерфейс, чтобы точно описать это. Если конкретная внутренняя реализация представляет собой каркасный класс с 100 членами, оберните его в свой собственный класс:

public interface ISmallSegregatedInterface
{
    void DoJustWhatMyClassNeeds();
}

public class TheImplementation : ISmallSegregatedInterface
{
    private readonly FrameworkClassWithLotsOfMembers _inner;

    public TheImplementation(FrameworkClassWithLotsOfMembers inner)
    {
        _inner = inner;
    }

    public void DoJustWhatMyClassNeeds()
    {
        _inner.CallSomeMethod();
    }
}

Теперь класс, который должен зависеть от одного метода, может зависеть от интерфейса только с этим одним методом. (Со временем я обнаружил, что это приводит к большому количеству интерфейсов с одним методом. Я думаю, что логически это приводит к зависимости от функций и делегатов, но интерфейс с одним методом - это нормально.

Это интерфейсная сегрегация. Ваши занятия не зависят от большого интерфейса, который им не нужен. Они зависят от одного или нескольких интерфейсов, которые точно описывают то, что им нужно. Это часто достигается созданием интерфейса с точки зрения класса, который должен зависеть от него.


Вы можете обнаружить, что ни один класс не должен зависеть от всех методов IServiceLocator.

Может быть, все, что вам нужно, это:

TService GetInstance<TService>();

Но действительно ли класс должен зависеть от метода, который может вернуть что-нибудь? Другими словами, вы, вероятно, будете запрашивать только одну или две зависимости. Так что, возможно, вам действительно нужно это:

public interface ISomethingSpecificFactory
{
    ISomethingSpecific CreateInstance();
}

Или вы можете обнаружить, что вам вообще не нужна фабрика - возможно, вы можете просто внедрить ISomethingSpecific вместо фабрики, которая создает экземпляр ISomethingSpecific.

Другой способ взглянуть на это: если вам не нужно реализовывать все методы IServiceLocator вам не нужно создавать класс, который реализует IServiceLocator.


IServiceLocator является интерфейсом фреймворка. В отличие от большинства программного обеспечения, которое мы создаем, оно не существует для удовлетворения узких, специфических потребностей. Он удовлетворяет более широкому спектру потребностей, которые определяются при написании нашего программного обеспечения. Вот почему имеет больше смысла, потому что он имеет все виды разнообразных методов, которые нам могут не понадобиться.

Одна из причин для провайдера заключается в том, что если множество классов зависят от разных членов интерфейса, мы можем быть вынуждены изменить интерфейс из-за потребностей одного клиента, и эти изменения влияют на других клиентов, которые зависят от других методов, в результате чего соединение их все вместе.

Мы не можем изменить IServiceLocator чтобы не было давления. Технически, даже если бы мы нарушили интернет-провайдера, полагаясь на этот интерфейс, это не имело бы вредного влияния, от которого нас защищает интернет-провайдер.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню