Шаблоны проектирования Часть вторая
Порождающие шаблоны —  Factory ( фабрика, фабричный метод) —  Abstract Factory  (абстрактная фабрика) —  Singleton ( одиночка) —  Lazy Load ( загрузка по требованию)
Façade  (фасад)
Façade  (фасад) class TreeNode { } class SearchResult { } static class ACAlgoritm { public static TreeNode BuildTree(string[] a_Keywords) { … } public static SearchResult[] FindAll(TreeNode a_Root, string a_Text) { … } } class SearchAlgoritm { TreeNode m_Root; public SearchAlgoritm(string[] a_Keywords) { m_Root = ACAlgoritm.BuildTree(a_Keywords); } public SearchResult[] FindAll(string a_Text) { return ACAlgoritm.FindAll(m_Root, a_Text); } public static SearchResult[] FindAll( string[] a_Keywords, string a_Text) { return ACAlgoritm.FindAll( ACAlgoritm.BuildTree(a_Keywords),  a_Text); } }
Façade  (фасад) —  Предоставить более удобный интерфейс для использования библиотеки, за счет наличия специальных удобных методов —  Повысить читаемость клиентского кода (повышение уровня абстракции) —  Снизить связанность между клиентским кодом и кодом модуля —  Создать собственный хорошо спроектированный  API  для сторонней библиотеки, у которой свой  API  плохо спроектирован
Composite ( компоновщик)
Composite ( компоновщик) select  *  from  Companies  where  (IsClient = 1  or  IsFormerClient = 1)  and  IsDeleted = 0  and  id_Object = 103
Composite ( компоновщик) IsClient = 1  or  IsFormerClient = 1)  and  IsDeleted = 0  and  id_Object = 103
Composite ( компоновщик) interface IFilter { string GetSql(); } interface ICompositeFilter : IFilter { void AddFilter(IFilter a_Filter); }
Composite ( компоновщик) class ScalarFilter : IFilter { string m_Sql; public ScalarFilter(string a_Field, string a_Relation, object a_Value) { m_Sql = string.Format("{0} {1} {2}", a_Field, a_Relation, a_Value); } public ScalarFilter(string a_Field, object a_Value) : this (a_Field, "=", a_Value) {} public string GetSql() { return m_Sql; } }
Composite ( компоновщик) class AndFilter : ICompositeFilter { List<IFilter> m_Filters = new List<IFilter>(); public void AddFilter(IFilter a_Filter) { m_Filters.Add(a_Filter); } public string GetSql() { string result = string.Empty; foreach (IFilter filter in m_Filters) { if (result != &quot;&quot;) result += &quot; and &quot;; result += filter.GetSql(); } return result; } }
Composite ( компоновщик) protected IFilter GetFilterInternal() {  XAndFilter result = new XAndFilter(); if (ObjectsItemSelection.HasSelectedItems) { XOrFilter objectFilter = new XOrFilter(); foreach (XObject obj in ObjectsItemSelection.SelectedItems)  objectFilter.Add(new XScalarFilter(&quot;id_Object&quot;, obj.Id));  result.Add(objectFilter); } if (OperatorCheckBox.Checked || ClientCheckBox.Checked || FormerClientCheckBox.Checked) { XAndFilter categoryFilter = new XAndFilter(); if (OperatorCheckBox.Checked) categoryFilter.Add(new XScalarFilter(&quot;IsOperator&quot;, 1)); if (ClientCheckBox.Checked) categoryFilter.Add(new XScalarFilter(&quot;IsClient&quot;, 1)); … result.Add(categoryFilter); } if (HoldingComboBox.Text.Trim() != &quot;&quot;) { result.Add(DB.Companies.HoldingFilter(HoldingComboBox.Text.Trim())); } … return result; }
Composite ( компоновщик) Компоновщик — это круто!
Ахтунг! public class XScalarFilter : IFilter { string m_Command; IDataParameter m_Parameter; public XScalarFilter(string a_Field, string a_Relation, object a_Value) {  int counter = XFilter.Counter; m_Command = string.Format(&quot;{0} {1} @p{2}&quot;, a_Field, a_Relation, counter); m_Parameter = new SqlParameter(); m_Parameter.Value = a_Value; m_Parameter.ParameterName = &quot;@p&quot; + counter; } public XScalarFilter(string a_Field, object a_Value) : this(a_Field, &quot;=&quot;, a_Value)   {} public string SqlText { get { return m_Command; } } public IList<IDataParameter> Parameters { get { return new IDataParameter[] { m_Parameter }; } } }
Задача
Command ( команда) interface ICommand { void Run(); } interface ICommand { void Do(); void UnDo(); } foreach(ICommand command in GetCommands()) { command.Do(); }
Command ( команда) <?xml version='1.0' encoding='windows-1251'?> <template> <parts> <part type=&quot;Cell&quot; cell=&quot;Contract&quot;> <sql>select ContractNumber from CompanyClients where id_Company = @id_Company</sql> </part> <part type=&quot;Cell&quot; cell=&quot;CompName&quot;> <sql>select FullName from Companies where id = @id_Company</sql> </part> <part type=&quot;Cell&quot; cell=&quot;SmallCompName&quot;> <sql>select FullName from Companies where id = @id_Company</sql> </part> <part type=&quot;Cell&quot; cell=&quot;Month&quot;> <sql>select @DateFrom</sql> </part> <part type=&quot;Table&quot; cell=&quot;AbonTable&quot; groupBy=&quot;BService&quot;> <sql> select ... </sql>  </part> </parts> </template>
Command ( команда)
Плагины [TemplateItem(TemplateKind.ExcelSpreadsheet, &quot;Cell&quot;)] public class XCellTemplateItem : XTemplateItem { public override void Apply() { XExcelWorkDesk wd = (XExcelWorkDesk)WorkDesk; … } } [TemplateItem(TemplateKind.ExcelSpreadsheet, &quot;Table&quot;)] class XTableTemplateItem : XTemplateItem { }
Плагины Type FindTypeByName(string a_Name) { foreach (Type type in GetType().Assembly.GetTypes()) { if (!type.IsSubclassOf(typeof(XTemplateItem))) { continue; } if (!type.IsDefined(typeof(TemplateItemAttribute), false)) { continue; } TemplateItemAttribute attr = (TemplateItemAttribute)type.GetCustomAttributes(typeof(TemplateItemAttribute), false)[0]; if (attr.TemplateKind == m_Template.TemplateKind && attr.Name == a_Name) { return type; } } return null; }
Template Method  ( шаблонный метод) abstract class Game  {  protected int playersCount;  protected  abstract void initializeGame();  protected  abstract void makePlay(int player);  protected  abstract bool endOfGame();  protected  abstract void printWinner(); /* A template method : */ public  void playOneGame(int playersCount) { this.playersCount = playersCount; initializeGame(); int j = 0; while (!endOfGame()) { makePlay(j); j = (j + 1) % playersCount; } printWinner(); } }
Template Method  ( шаблонный метод) abstract public class XParser { public XCallInformation ParseAndProcess(XBillingString a_BillingString) { a_BillingString.SetParser(this); XCallInformation result = DoParse(a_BillingString); if (result == null) { XBilling.RegisterError(a_BillingString); } return result; } public XCallInformation Parse(XBillingString a_BillingString) { a_BillingString.SetParser(this); return DoParse(a_BillingString); } }
Strategy ( стратегия) class XDocumentConflictManager { public XDocumentConflict FindConflict( XDocument a_Document, bool a_ForRegisteration) { XDocumentConflictFindingStrategy strategy =  XDocumentConflictFindingStrategy.Create(a_Document, a_ForRegisteration); return new XDocumentConflict( a_Document,  strategy.FindSameDocuments(),  strategy); } }
Strategy ( стратегия) public abstract class XDocumentConflictFindingStrategy { XDocument m_Document; protected XDocumentConflictFindingStrategy(XDocument a_Document) { m_Document = a_Document; } public static XDocumentConflictFindingStrategy Create(XDocument a_Document, bool a_ForRegistration) { … } public IList<XDocument> FindSameDocuments() { return XDocumentRepository.Instance.Find(GetSameDocumentsFilter()); } protected abstract IFilter GetSameDocumentsFilter(); public abstract string GetConflictDefinition(); }
Strategy ( стратегия) public class XBillingConflictFindingStrategy : XDocumentConflictFindingStrategy { internal XBillingConflictFindingStrategy(XDocument a_Document) : base(a_Document) { } protected override IFilter GetSameDocumentsFilter() { return new XAndFilter( DB.vDocuments.idFilter(&quot;!=&quot;, Document.Id), DB.vDocuments.id_CompanyFilter(Document.Company.Id), DB.vDocuments.DocumentDateFilter(Document.DocumentDate), DB.vDocuments.id_TemplateFilter(Document.Template.Id) ); } public override string GetConflictDefinition() { return string.Format(&quot;Компания «{0}» уже имеет расшифровку «{1}» за «{2:MMMM yyyy}».&quot;, Document.Company.Alias, Document.Template.Name, Document.DocumentDate); } }

Шаблоны проектирования 2

  • 1.
  • 2.
    Порождающие шаблоны — Factory ( фабрика, фабричный метод) — Abstract Factory (абстрактная фабрика) — Singleton ( одиночка) — Lazy Load ( загрузка по требованию)
  • 3.
  • 4.
    Façade (фасад)class TreeNode { } class SearchResult { } static class ACAlgoritm { public static TreeNode BuildTree(string[] a_Keywords) { … } public static SearchResult[] FindAll(TreeNode a_Root, string a_Text) { … } } class SearchAlgoritm { TreeNode m_Root; public SearchAlgoritm(string[] a_Keywords) { m_Root = ACAlgoritm.BuildTree(a_Keywords); } public SearchResult[] FindAll(string a_Text) { return ACAlgoritm.FindAll(m_Root, a_Text); } public static SearchResult[] FindAll( string[] a_Keywords, string a_Text) { return ACAlgoritm.FindAll( ACAlgoritm.BuildTree(a_Keywords), a_Text); } }
  • 5.
    Façade (фасад)— Предоставить более удобный интерфейс для использования библиотеки, за счет наличия специальных удобных методов — Повысить читаемость клиентского кода (повышение уровня абстракции) — Снизить связанность между клиентским кодом и кодом модуля — Создать собственный хорошо спроектированный API для сторонней библиотеки, у которой свой API плохо спроектирован
  • 6.
  • 7.
    Composite ( компоновщик)select * from Companies where (IsClient = 1 or IsFormerClient = 1) and IsDeleted = 0 and id_Object = 103
  • 8.
    Composite ( компоновщик)IsClient = 1 or IsFormerClient = 1) and IsDeleted = 0 and id_Object = 103
  • 9.
    Composite ( компоновщик)interface IFilter { string GetSql(); } interface ICompositeFilter : IFilter { void AddFilter(IFilter a_Filter); }
  • 10.
    Composite ( компоновщик)class ScalarFilter : IFilter { string m_Sql; public ScalarFilter(string a_Field, string a_Relation, object a_Value) { m_Sql = string.Format(&quot;{0} {1} {2}&quot;, a_Field, a_Relation, a_Value); } public ScalarFilter(string a_Field, object a_Value) : this (a_Field, &quot;=&quot;, a_Value) {} public string GetSql() { return m_Sql; } }
  • 11.
    Composite ( компоновщик)class AndFilter : ICompositeFilter { List<IFilter> m_Filters = new List<IFilter>(); public void AddFilter(IFilter a_Filter) { m_Filters.Add(a_Filter); } public string GetSql() { string result = string.Empty; foreach (IFilter filter in m_Filters) { if (result != &quot;&quot;) result += &quot; and &quot;; result += filter.GetSql(); } return result; } }
  • 12.
    Composite ( компоновщик)protected IFilter GetFilterInternal() { XAndFilter result = new XAndFilter(); if (ObjectsItemSelection.HasSelectedItems) { XOrFilter objectFilter = new XOrFilter(); foreach (XObject obj in ObjectsItemSelection.SelectedItems) objectFilter.Add(new XScalarFilter(&quot;id_Object&quot;, obj.Id)); result.Add(objectFilter); } if (OperatorCheckBox.Checked || ClientCheckBox.Checked || FormerClientCheckBox.Checked) { XAndFilter categoryFilter = new XAndFilter(); if (OperatorCheckBox.Checked) categoryFilter.Add(new XScalarFilter(&quot;IsOperator&quot;, 1)); if (ClientCheckBox.Checked) categoryFilter.Add(new XScalarFilter(&quot;IsClient&quot;, 1)); … result.Add(categoryFilter); } if (HoldingComboBox.Text.Trim() != &quot;&quot;) { result.Add(DB.Companies.HoldingFilter(HoldingComboBox.Text.Trim())); } … return result; }
  • 13.
    Composite ( компоновщик)Компоновщик — это круто!
  • 14.
    Ахтунг! public classXScalarFilter : IFilter { string m_Command; IDataParameter m_Parameter; public XScalarFilter(string a_Field, string a_Relation, object a_Value) { int counter = XFilter.Counter; m_Command = string.Format(&quot;{0} {1} @p{2}&quot;, a_Field, a_Relation, counter); m_Parameter = new SqlParameter(); m_Parameter.Value = a_Value; m_Parameter.ParameterName = &quot;@p&quot; + counter; } public XScalarFilter(string a_Field, object a_Value) : this(a_Field, &quot;=&quot;, a_Value) {} public string SqlText { get { return m_Command; } } public IList<IDataParameter> Parameters { get { return new IDataParameter[] { m_Parameter }; } } }
  • 15.
  • 16.
    Command ( команда)interface ICommand { void Run(); } interface ICommand { void Do(); void UnDo(); } foreach(ICommand command in GetCommands()) { command.Do(); }
  • 17.
    Command ( команда)<?xml version='1.0' encoding='windows-1251'?> <template> <parts> <part type=&quot;Cell&quot; cell=&quot;Contract&quot;> <sql>select ContractNumber from CompanyClients where id_Company = @id_Company</sql> </part> <part type=&quot;Cell&quot; cell=&quot;CompName&quot;> <sql>select FullName from Companies where id = @id_Company</sql> </part> <part type=&quot;Cell&quot; cell=&quot;SmallCompName&quot;> <sql>select FullName from Companies where id = @id_Company</sql> </part> <part type=&quot;Cell&quot; cell=&quot;Month&quot;> <sql>select @DateFrom</sql> </part> <part type=&quot;Table&quot; cell=&quot;AbonTable&quot; groupBy=&quot;BService&quot;> <sql> select ... </sql> </part> </parts> </template>
  • 18.
  • 19.
    Плагины [TemplateItem(TemplateKind.ExcelSpreadsheet, &quot;Cell&quot;)]public class XCellTemplateItem : XTemplateItem { public override void Apply() { XExcelWorkDesk wd = (XExcelWorkDesk)WorkDesk; … } } [TemplateItem(TemplateKind.ExcelSpreadsheet, &quot;Table&quot;)] class XTableTemplateItem : XTemplateItem { }
  • 20.
    Плагины Type FindTypeByName(stringa_Name) { foreach (Type type in GetType().Assembly.GetTypes()) { if (!type.IsSubclassOf(typeof(XTemplateItem))) { continue; } if (!type.IsDefined(typeof(TemplateItemAttribute), false)) { continue; } TemplateItemAttribute attr = (TemplateItemAttribute)type.GetCustomAttributes(typeof(TemplateItemAttribute), false)[0]; if (attr.TemplateKind == m_Template.TemplateKind && attr.Name == a_Name) { return type; } } return null; }
  • 21.
    Template Method ( шаблонный метод) abstract class Game { protected int playersCount; protected abstract void initializeGame(); protected abstract void makePlay(int player); protected abstract bool endOfGame(); protected abstract void printWinner(); /* A template method : */ public void playOneGame(int playersCount) { this.playersCount = playersCount; initializeGame(); int j = 0; while (!endOfGame()) { makePlay(j); j = (j + 1) % playersCount; } printWinner(); } }
  • 22.
    Template Method ( шаблонный метод) abstract public class XParser { public XCallInformation ParseAndProcess(XBillingString a_BillingString) { a_BillingString.SetParser(this); XCallInformation result = DoParse(a_BillingString); if (result == null) { XBilling.RegisterError(a_BillingString); } return result; } public XCallInformation Parse(XBillingString a_BillingString) { a_BillingString.SetParser(this); return DoParse(a_BillingString); } }
  • 23.
    Strategy ( стратегия)class XDocumentConflictManager { public XDocumentConflict FindConflict( XDocument a_Document, bool a_ForRegisteration) { XDocumentConflictFindingStrategy strategy = XDocumentConflictFindingStrategy.Create(a_Document, a_ForRegisteration); return new XDocumentConflict( a_Document, strategy.FindSameDocuments(), strategy); } }
  • 24.
    Strategy ( стратегия)public abstract class XDocumentConflictFindingStrategy { XDocument m_Document; protected XDocumentConflictFindingStrategy(XDocument a_Document) { m_Document = a_Document; } public static XDocumentConflictFindingStrategy Create(XDocument a_Document, bool a_ForRegistration) { … } public IList<XDocument> FindSameDocuments() { return XDocumentRepository.Instance.Find(GetSameDocumentsFilter()); } protected abstract IFilter GetSameDocumentsFilter(); public abstract string GetConflictDefinition(); }
  • 25.
    Strategy ( стратегия)public class XBillingConflictFindingStrategy : XDocumentConflictFindingStrategy { internal XBillingConflictFindingStrategy(XDocument a_Document) : base(a_Document) { } protected override IFilter GetSameDocumentsFilter() { return new XAndFilter( DB.vDocuments.idFilter(&quot;!=&quot;, Document.Id), DB.vDocuments.id_CompanyFilter(Document.Company.Id), DB.vDocuments.DocumentDateFilter(Document.DocumentDate), DB.vDocuments.id_TemplateFilter(Document.Template.Id) ); } public override string GetConflictDefinition() { return string.Format(&quot;Компания «{0}» уже имеет расшифровку «{1}» за «{2:MMMM yyyy}».&quot;, Document.Company.Alias, Document.Template.Name, Document.DocumentDate); } }