1

У меня есть библиотека классов, в которой описываются различные компоненты соединительного оборудования, такие как гвозди, винты и болты, которые мы будем называть ConnectorLibrary. Я пытаюсь создать библиотеку поверх той, которая будет обрабатывать анализ пропускной способности каждого класса в этой библиотеке, которую мы будем называть ConnectorGripAnalysisLibrary.Имитация наследования с помощью расширения

По этому вопросу мы будем работать с классами: Screw, Bolt и Connector. Оба Screw и Bolt наследуют от Connector (который является абстрактным классом), и оба они реализованы в ConnectorLibrary.

Существует другой метод определения захвата для каждого класса в базовой библиотеке, который мне нужно реализовать. Итак, для обоих Bolt и Screw Мне нужно реализовать такой метод, как DoesPassGripTest(Board board). (Правление является только примерным параметром)

Если бы я собирался реализовать это в Connectorlibrary, я бы поставил DoesPassGripTest в Connector абстрактным методом и реализовал различные формулы в соответствующих производных классах.

Цель состоит в том, чтобы быть в состоянии иметь мой код работу, как это от ConnectorGripAnalysisLibrary:

[Test()] 
public static void CheckScrewAndBoltGripTest() 
{ 
    Board board = new Board(); 

    Bolt b = new Bolt(); 
    Screw s = new Screw(); 
    List<Connector> connectors = new List<Connector>() 

    connectors.add(b); 
    connectors.add(s); 

    foreach(var connector in connectors) 
    { 
     if(!connector.DoesPassGripTest(board)); 
      throw new Exception("Grip Test Fails"); 
    } 
} 

Я хочу, чтобы поддерживать «Открытый закрытый принцип» в ConnectorGripAnalysisLibrary, так что в случае нового коннектор добавляется в ConnectorLibary, никакая модификация библиотеки ConnectorGripAnalysisLibrary не требуется, кроме добавления нового класса. «Open for Extension, Closed for Modificaiton»

Но как я могу создать эту функциональность в GripAnalysisLibrary, которая построена поверх ConnectorLibrary. Есть ли способ сделать это?

Я не хочу, чтобы ConnectorLibrary содержала код и функциональность GripAnalysis. Библиотека ConnectorLibrary должна быть открыта, тогда как GripAnalysisLibrary будет запатентованной.

+0

, что примерно через интерфейс, так что каждый тип реализует 'DoesPassGripTest' делать все, что ему нужно? – Plutonix

+0

@Plutonix Как реализовать интерфейсы по расширению без получения нового типа? – jth41

+0

Почему это необходимо * для расширения? – Plutonix

ответ

0

Для делать это в качестве метода расширения вам необходимо создать класс для определения расширений для Connector и включают в себя класс, где вы хотите использовать метод DoesPassGripTest на экземпляре Connector. Основной план расширения является:

public static class ConnectorExtensions 
{ 
    public static bool DoesPassGripTest(this Connector connector, Board board) 
    { 
     // Some logic to determine which connector is being used 
    } 
} 

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

EDIT:

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

Создайте интерфейс, который поставляет информацию для выполнения анализа и какой тип коннектора он для:

public interface IConnectorGripAnalyzer 
{ 
    Type ConnectorType { get; } 
    bool DoesPassGripTest(Board board); 
} 

Создать базовый класс с помощью дженериков для простых реализаций конкретных классов:

public class ConnectorGripAnalyzer<T> : IConnectorGripAnalyzer where T : Connector 
{ 
    public Type ConnectorType 
    { 
     get { return typeof(T); } 
    } 

    public virtual bool DoesPassGripTest(Board board) 
    { 
     return true; 
    } 
} 

Создайте репозиторий, который можно использовать для получения экземпляра IConnectorGripAnalyzer по типу с использованием отражения. При первом использовании он собирает все различные анализаторы и сохраняют их с помощью разъема Типа:

public static class ConnectorAnalyzerRepository 
{ 
    private Dictionary<Type, IConnectorGripAnalyzer> connectorGripAnalyzers; 

    public IConnectorGripAnalyzer GetGripAnalyzer(Connector connector) 
    { 
     if (connectorGripAnalyzers == null) 
     { 
      connectorGripAnalyzers = new Dictionary<Type, IConnectorGripAnalyzer>(); 

      var types = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(IConnectorGripAnalyzer).IsAssignableFrom(t)); 
      foreach (var t in types) 
      { 
       var c = Activator.CreateInstance(t) as IConnectorGripAnalyzer; 
       if (c == null) 
        continue; 

       connectorGripAnalyzers[c.ConnectorType] = c; 
      } 
     } 

     return connectorGripAnalyzers.ContainsKey(typeof(connector)) ? connectorGripAnalyzers[typeof(connector)] : null; 
    } 
} 

Расширения для Connector использует репозиторий для создания соответствующего экземпляра IConnectorGripAnalyzer для данного соединителя. В том случае, когда тип коннектора не имеет реализации пример генерирует исключение, но вы могли бы вернуть ложные или зарегистрировать ее как вопрос конфигурации, а также:

public static class ConnectorExtensions 
{ 
    public static bool DoesPassGripTest(this Connector connector, Board board) 
    { 
     var analyzer = ConnectorAnalyzerRepository.GetGripAnalyzer(connector); 
     if (analyzer == null) 
      throw new ArgumentException("Invalid connector type"); // Do whatever you want with the failure 

     return analyzer.DoesPassGripTest(board); 
    } 
} 

Добавление поддержки для соединителя в ConnectorGripAnalysisLibrary сейчас вопрос о добавлении класса, который наследует от ConnectorGripAnalyzer с конкретным типом коннектора. Все, что требуется, это соответствующее переопределение DoesPassGripTest(Board board) для конкретного коннектора:

public class NailConnectorGripAnalyzer : ConnectorGripAnalyzer<NailConnector> 
{ 
    public override bool DoesPassGripTest(Board board) 
    { 
     return true; 
    } 
} 

public class ScrewConnectorGripAnalyzer : ConnectorGripAnalyzer<ScrewConnector> 
{ 
    public override bool DoesPassGripTest(Board board) 
    { 
     return true; 
    } 
} 
+0

Я понимаю это решение, но я бы предпочел не использовать его, потому что он нарушает открытый-закрытый принцип и требует изменения каждый раз, когда в ConnectorLibrary добавляется новый 'Connector'. – jth41

+0

Я согласен с тем, что вы говорите. Я просто предоставлял реализацию подхода расширения, который будет работать с кодом клиента, который вы хотите использовать. Разделяют ли ваши соединители любую другую идентифицирующую информацию как часть их открытого интерфейса? – musicfuel

Смежные вопросы