У меня есть сборка .NET, которую я создаю, и я хочу, чтобы конечный пользователь мог видеть только несколько классов и методов. Я создаю сборку с проектом класса библиотеки в рамках 4.5 с Visual Studio 2015. Сборка предоставит консоль управления для управления некоторыми взаимосвязанными бэкэнд-услугами и приложениями. Большая часть работы будет происходить в сборке и будет невидимой для конечного пользователя. Большинство классов в пространстве имен сборки будут внутренними и поэтому невидимыми для конечного пользователя; но сборка предоставит несколько общедоступных классов и методов, с которыми может взаимодействовать конечный пользователь. Как я это себе представляю, сборка предоставит открытый статический класс, в котором конечный пользователь будет передавать параметры, необходимые сборке, а затем вернуть объект, который может использовать конечный пользователь. Например, вот шаблон псевдокода того, что этот открытый статический класс может выглядеть концептуально.Как реализовать инъекцию зависимостей Setter от внутренних модификаторов доступа
public static class ControlClientStarter
{
public static ISrvcManagerConsole GetSrvcManagerConsole(/*. all the parameters . */)
{
// Some code that parses the parameters . . .
ISrvc_Controller accountController = new AccountSrvc_Controller(/*. . . */);
ISrvc_Controller contractController = new ContractSrvc_Controller(/*. . . */);
ISrvc_Controller imageController = new ImageSrvc_Controller(/*. . . */);
ICatalogApp_Controller calatlogController = new CatalogApp_Controller(/*. . . */);
IPortal_Controller portalController = new PortalSrvc_Controller(/*. . . */);
ISrvcManagerConsole srvcMngrConsole = new SrvceManagerConsole(
accountController,
contractController,
imageController,
calatlogController,
portalController);
return srvcMngrConsole;
}
}
Код выше показывает, что сборка .dll обеспечивает публичный статический класс с именем ControlClientStarter, который имеет один публичный статический метод GetSrvcManagerConsole() (...). Этот статический метод принимает несколько параметров, а затем на основе этих параметров и различной логики создает объекты, которые реализуют интерфейс ISrvc_Controller, а также другие объекты, которые реализуют другие интерфейсы. Эти объекты вводятся в конструктор объекта srvcMngrConsole и возвращают это конечному пользователю.
Конечный пользователь получит доступ к управляющей консоли с чем-то концептуально похожее на это,
ISrvcManagerConsole clientMngrConsole = ControlClientStarter.GetSrvcManagerConsole( /*. . . */);
clientMngrConsole.DoThis( /*. . . */);
clientMngrConsole.StopThis( /*. . . */);
clientMngrConsole.GetThat( /*. . . */);
clientMngrConsole.PublishThat( /*. . . */);
Внутри консоли управления может выглядеть отвлеченно, как этот псевдокод, где аргументы, переданные в SrvcManagerConsole спасаются интерфейс реализации поля внутри объекта srvcMngrConsole,
internal class SrvcManagerConsole : ISrvcManagerConsole
{
ISrvc_Controller accountController ;
ISrvc_Controller contractController ;
ISrvc_Controller imageController ;
ICatalogApp_Controller calatlogController;
IPortal_Controller portalController ;
internal SrvcManagerConsole(
ISrvc_Controller accountController,
ISrvc_Controller contractController,
ISrvc_Controller imageController,
ICatalogApp_Controller calatlogController,
IPortal_Controller portalController)
{
this.accountController = accountController;
this.contractController = contractController;
this.imageController = imageController;
this.calatlogController = calatlogController;
this.portalController = portalController;
}
public void DoThis(/*. . . */)
{ /*. . . */ }
public void StopThis(/*. . . */)
{ /*. . . */ }
public void GetThat(/*. . . */)
{ /*. . . */ }
public void PublishThat(/*. . . */)
{ /*. . . */ }
// private and-or internal methods and properties . . .
}
Как вы можете видеть, я использую инъекции в конструкторе зависимостей, чтобы избежать сильной связи; но есть проблема с этим. Что делать, если в будущем я хочу добавить MapPublishApp_Controller, VideoSrvc_Controller и т. Д.?
Если я добавлю их в конструктор после первой версии, тогда другой код, который уже использует эту сборку, также должен измениться. Если я добавлю еще один конструктор SrvceManagerConsole с дополнительными параметрами, которые берут новые контроллеры, то я не буду нарушать предыдущий код, но параметры конструктора начнут становиться слишком многочисленными. Кроме того, в зависимости от параметров, которые конечный пользователь отправляет методу GetSrvcManagerConsole() класса ControlClientStarter, я, возможно, не захочу использовать все контроллеры. Было бы намного лучше, если бы у меня были методы, которые добавляют контроллеры в поля. Задача состоит в том, что я не хочу, чтобы конечный пользователь имел доступ к этим полям. Я хочу, чтобы сборка создавала экземпляры классов контроллера и назначала скрытые поля. Если я дам эти методы присваивания в модификаторах внутреннего доступа класса SrvceManagerConsole, метод GetSrvcManagerConsole() не сможет их увидеть, потому что он является общедоступным.
Обратите внимание на модификаторы доступа на интерфейсах. Единственный публичный - это тот, который реализуется классом SrvcManagerConsole. Остальные являются внутренними, потому что они не должны быть доступны конечному пользователю.
internal interface ISrvc_Controller { /*. . . */ }
internal interface ICatalogApp_Controller { /*. . . */ }
internal interface IPortal_Controller { /*. . . */ }
public interface ISrvcManagerConsole
{
void DoThis(/*. . . */);
void StopThis(/*. . . */);
void GetThat(/*. . . */);
void PublishThat(/*. . . */);
}
Эти методы, как выше PublishThat() будет использовать поля, которые получили установленные на объекты, инжектированных в конструктор.Программист конечного пользователя, который использует мою сборку, никогда не увидит эти интерфейсы, реализующие экземпляры. Объект clientMngrConsole, созданный программистом конечного пользователя, будет использовать эти внутренние объекты без программиста, даже зная, как они используются.
Классы, реализующие интерфейсы с модификаторами доступа к внутренним бы отвлеченно быть что-то вроде этого,
class AccountSrvc_Controller : ISrvc_Controller { /*. . . */ }
class ContractSrvc_Controller : ISrvc_Controller { /*. . . */ }
class ImageSrvc_Controller : ISrvc_Controller { /*. . . */ }
class CatalogApp_Controller : ICatalogApp_Controller { /*. . . */ }
class PortalSrvc_Controller : IPortal_Controller { /*. . . */ }
Там может быть несколько классов контроллеров в будущем, может быть, нет. Мне не удалось выяснить, как назначить классы контроллеров для задних полей таким образом, чтобы эти поля были недоступны для конечного пользователя, сохраняя при этом некоторый уровень ослабленной связи, поскольку выполнение этих контроллеров необходимо изменить в будущее. Я обнаружил, однако, что, если другие методы и свойства указаны в интерфейсе ISrvceManagerConsole, и этот интерфейс задан с помощью общедоступного модификатора, эти методы и свойства в классе SrvceManagerConsole, который реализует этот интерфейс, также могут быть установлены как общедоступные и успешно достигнутый, несмотря на то, что сам класс SrvceManagerConsole задан как «внутренний». Я попробовал установку setterter, но C# (мудро) не поддерживает свойство с интерфейсом backend (потому что это не имеет никакого смысла). Другая возможность состоит в том, чтобы конструктор SrvceManagerConsole использовал один параметр, который, возможно, обертывает все другие экземпляры интерфейса в словаре. Я еще не пробовал. Я не могу быть первым, кто столкнулся с этим. Должно быть общее решение, которое я не смог найти. Я знаю, что отраслевым стандартом является использование контейнеров IoC для того, что я делаю выше, но это не будет сделано здесь. Я никогда раньше не пробовал такую архитектуру. Я знаю, что это, вероятно, не лучшая архитектура; но пока это не должно быть точно в соответствии с некоторой чрезмерно сложной архитектурой. Я собираюсь создать адекватный дизайн, поскольку я больше об этом узнаю.
Edit # 1, почему шаблон Builder не работает здесь
Предположим, что я пытаюсь избежать конструктора антишаблоном, используя шаблон строитель, как показано ниже псевдокоде.
Представьте, что SrvcManagerConsole выглядит следующим образом:
internal class SrvcManagerConsole : ISrvcManagerConsole
{
internal ISrvc_Controller accountController;
internal SrvcManagerConsole() { }
internal void AddAccountController(ISrvc_Controller accountController)
{
this.accountController = accountController;
}
}
Представьте изменить ControlClientStarter на что-то вроде этого:
public static class ControlClientStarter
{
public static ISrvcManagerConsole GetSrvcManagerConsole(/*. all the parameters . */)
{
Federated_ControlBuilder fedBuilder = new Federated_ControlBuilder();
ISrvcManagerConsole srvcMngrConsole = fedBuilder.GetSrvcManagerConsole();
return srvcMngrConsole;
}
}
И тогда я реализовать Federated_ControlBuilder так:
internal class Federated_ControlBuilder : IControl_Builder
{
internal ISrvcManagerConsole srvcMngrConsole;
internal Federated_ControlBuilder()
{
srvcMngrConsole = new SrvcManagerConsole();
}
public void InjectAccountController(ISrvc_Controller accountController)
{
// The srvcMngrConsole object can not see the InjectAccountController method.
// srvcMngrConsole.
}
internal ISrvcManagerConsole GetSrvcManagerConsole()
{
return srvcMngrConsole;
}
}
Метод InjectAccountController (...) для Federated_Contr Класс olBuilder не может видеть метод AddAccountController (...) класса SrvcManagerConsole, потому что он является внутренним.
Точка зрения моего вопроса заключается не в том, как избежать конструктора анти-шаблона сами по себе; но задача состоит в том, чтобы избежать анти-шаблона, делая определенные классы и методы в сборке недоступными для конечного пользователя-программиста, следовательно, использование слова «внутренний» заголовок вопроса «Как реализовать зависимость сеттера Инъекция на внутренних Модификаторы доступа.«
Если бы это был всего лишь вопрос об избегании конструктора анти-шаблона, я мог бы публиковать открытые поля SrvcManagerConsole и добавлять их непосредственно через метод GetSrvcManagerConsole (...) класса ControlClientStarter.
Благодарим вас за рекомендацию. Это ценно. Я ответил на мой исходный пост после раздела «Редактировать # 1 ...». – Beebok