Смотря как реализовать простой полиморфизм

У меня очень основной вопрос (я не знаю, почему я не могу думать прямо).

Я пытаюсь сделать некоторый полиморфизм.

У меня интерфейс выглядит так:

Public interface Iplugin
{

   void doSomthing(string _str);
}

У меня также есть несколько классов плагинов, которые поддерживают этот интерфейс

public class plugin1:Iplugin
{
    void doSomthing(string _str)
    {
        if (_str=="1")
        {
           // do somthing 1
        }
     }
 }

 public class plugin2:Iplugin
{
    void doSomthing(string _str)
    {
        if (_str=="2")
        {
           // do somthing 2
        }
     }
 }

public class plugin3:Iplugin
{
    void doSomthing(string _str)
    {
        if (_str=="3")
        {
           // do somthing 3
        }
     }
 }

Итак, у меня есть основной класс, и я хотел бы вызвать плагин all

НО я хотел бы сохранить OCP (принцип Open-Closed), поэтому, если я добавлю в будущем еще один класс плагинов, основной класс не изменится.

Это основной класс

public class mainApp
{
  Iplugin _context;
  mainApp()
  {
     _context= new //new what??
  }
  bool func(string str)
  {
      _context.doSomthing(str);//I would like it to invoke all the plug in and also a future plugins that I will add
  }
} 

4 ответа

Решение

Хорошо, спасибо всем за вашу помощь.

Я принимаю все ваши советы, и я сделал следующее:

 namespace Plugins
{




 public class plugin1 : Iplugin
  {
    void doSomthing(string _str)
    {
        if (_str == "1")
        {
            // do somthing 1
        }
    }


}

public class plugin2 : Iplugin
{
    void doSomthing(string _str)
    {
        if (_str == "2")
        {
            // do somthing 2
        }
    }


}

public class plugin3 : Iplugin
{
    void doSomthing(string _str)
    {
        if (_str == "3")
        {
            // do somthing 3
        }
    }


 }
}

Так что это пространство имен со всеми плагинами

сейчас в основном приложении

namespace Factory
{
  public interface Iplugin
  {

    void doSomthing(string _str);
  }



class Program
{
    static void Main(string[] args)
    {
        string @namespace = "Plugins";

        var q = from t in Assembly.GetExecutingAssembly().GetTypes()
                where t.IsClass && t.Namespace == @namespace
                select t;
        q.ToList();

        List<Iplugin> myList = new List<Iplugin>();
        foreach (var item in q)
        {
            Iplugin temp=(Iplugin)Activator.CreateInstance(item);
            myList.Add(temp);// a list with all my plugins

        }

        foreach (var item in myList)
        {
           item.doSomthing("string");

        }

    }
}

}

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

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

[PluginAttribute("myPlugin")]
class MyPlugin : IPlugin

теперь фабрика первоначально проверяет все классы во всех загруженных сборках и ищет атрибут и сохраняет тип и идентификатор строки плагина в словаре.

class PluginFactory
{
    static Iplugin CreatePlugin(string aName)
    {
        return Activator.CreateInstance( sRegisteredPlugins[aName]);
    }

    private static Dictionary<string, Type> sRegisteredPlugins;
}

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

И как уже упоминалось @Ian, вы должны объявить doSomthingvirtual чтобы это работало правильно.

public class mainApp
{
  mainApp()
  {
    List<Iplugin> plugins = new ArrayList<Iplugin>;

    ...

    plugins.add(new plugin1());
    ...
    plugins.add(new plugin3());
    ...
    func(plugins, "1");
    ...
    func(plugins, "7");
  }

  bool func(List<IPlugin> plugins, string str)
  {
    foreach (IPlugin plugin in plugins) {
      plugin.doSomthing(str);
    }
  }
}

Это упрощенный пример Dependency Injection, которое является одним из хорошо известных приложений полиморфизма (ну, чтобы сделать его реальным DI, вы должны поставить func в другой класс). Чтобы сделать ваш код более гибким и отделить создание ваших плагинов от их использования, вы также можете использовать, например, Factory Method или Builder.

Другие вопросы по тегам