Как написать шаблон локатора службы, в котором конкретные классы реализуют один и тот же интерфейс/службу?

Рассмотрим ниже

class ServiceA : IServiceA
    {
        public void SayHelloFromA()
        {
            Console.WriteLine("Hello Service A");
            Console.ReadKey();
        }
    }    
    class ServiceB : IServiceB{ } 
    class ServiceC : IServiceC{ }
    interface IServiceA 
    { 
        void SayHelloFromA(); 
    }
    interface IServiceB{ }
    interface IServiceC{ }

Если я хочу использовать шаблон Service Locator, приведенный пример здесь работает отлично.

Теперь предположим, что другой класс реализует интерфейс IServiceA, как показано ниже.

class ServiceA1 : IServiceA
{
    public void SayHelloFromA()
    {
        Console.WriteLine("Hello Service A1");
        Console.ReadKey();
    }
} 

И соответственно мне нужно добавить сервис в словарь как в

internal ServiceLocator()    
        {        
            services = new Dictionary<object, object>();         

            this.services.Add(typeof(IServiceA), new ServiceA());
            this.services.Add(typeof(IServiceA), new ServiceA1());     
            this.services.Add(typeof(IServiceB), new ServiceB());        
            this.services.Add(typeof(IServiceC), new ServiceC());    
        } 

И это неправильно, так как в словаре не может быть дубликатов ключей.

Итак, как я могу решить эту проблему? Как должна быть изменена структура данных, чтобы локатор службы мог вместить и то, и другое.

N.B.~ Я пытаюсь реализовать шаблон Srvice Locator в своем фабричном методе.

public class CustomerFactory : ICustomerBaseFactory

{

          public IBaseCustomer  GetCustomer(string  CustomerType)

          { 
                   switch(CustomerType)

                   { 
                             case "1": return  new Grade1Customer(); break;

                             case "2": return new Grade2Customer(); break;

                             default:return null; 
                   } 
          } 
}

где бетонные заводы происходят от IBaseCustomer

Спасибо


person priyanka.sarkar    schedule 25.03.2013    source источник
comment
Как бы вы получили конкретную реализацию? Весь смысл локатора сервисов в том, чтобы предоставить вам реализацию IServiceA, не зная, какую именно. В вашем примере, как бы вы вызвали локатор службы, чтобы получить конкретную реализацию? (при условии, что у вас может быть ключевой контейнер с дубликатами)   -  person Seb    schedule 25.03.2013


Ответы (2)


Рассматривали ли вы словарь для каждого абстрактного типа с ключом конкретного типа, вложенного в словарь верхнего уровня?

Dictionary<T, Dictionary<T, U>>

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

e.g.

var services = new Dictionary<Type, Dictionary<Type, Object>>();

Теперь вы можете запросить словарь сервисов для типа:

services.TryGetValue(typeof(IServiceA), componentDictionary);

Если это возвращает true, вы знаете, что componentDictionary будет содержать компоненты, реализующие эту службу:

foreach (c in componentDictionary.Values) {... }

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

person David Osborne    schedule 25.03.2013
comment
Я обновил ответ, чтобы немного продемонстрировать концепцию. По сути, вашему локатору сервисов нужна Identity Map для хранения/преобразования компонентов в сервисы. - person David Osborne; 25.03.2013

В Java есть класс MultiMap, который поддерживает несколько значений для каждого ключа. Я уверен, что вы можете найти аналогичную структуру данных и для C#.

person Param    schedule 26.03.2013
comment
Однако это не часть JDK. Если вам нужно использовать чистую Java, используйте Map со значениями List. Дополнительная информация: docs.oracle.com/javase/tutorial/collections/interfaces /map.html - person Artem Malchenko; 25.04.2020