227 lines
6.3 KiB
C#
227 lines
6.3 KiB
C#
/*
|
||
* ПАТТЕРНЫ ПОВЕДЕНИЯ
|
||
*
|
||
* Глава_2 и 10: Фабричный метод(виртуальный конструктор) и Шаблонный метод (Паттерн поведения)
|
||
*
|
||
* — это каркас, в который наследники могут
|
||
* подставить реализации недостающих элементов.
|
||
*
|
||
* - позволяет более четко определить «контракт» между базовым классом и потомками
|
||
*/
|
||
|
||
using Behavioral;
|
||
using Creational;
|
||
using System.ServiceModel;
|
||
using System.Text;
|
||
|
||
/*
|
||
* Теперь все реализации читателей логов будут вынуждены следовать согласованному протоколу
|
||
*/
|
||
public abstract class LogReader
|
||
{
|
||
private int _currentPosition;
|
||
|
||
/// <summary>
|
||
/// Определяет алгоритм импорта
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public IEnumerable<LogEntry> ReadLogEntry()
|
||
{
|
||
return ReadEntries(ref _currentPosition).Select(ParseLogEntry);
|
||
}
|
||
|
||
protected abstract IEnumerable<string> ReadEntries(ref int position);
|
||
|
||
protected abstract LogEntry ParseLogEntry(string stringEntry);
|
||
}
|
||
|
||
/*
|
||
* 2.1: Локальный шаблонный метод на основе делегатов
|
||
*
|
||
* ! является более контекстно зависимой операцией
|
||
*
|
||
* Использование наследования является слишком тяжеловесным решением,
|
||
* поэтому в таких случаях применяется подход, при котором переменный шаг алгоритма задается делегатом
|
||
*/
|
||
|
||
/// <summary>
|
||
/// Поведение сервиса сохранения записей
|
||
/// </summary>
|
||
interface ILogSaver
|
||
{
|
||
void UploadLogEntries(IEnumerable<LogEntry>logEntries);
|
||
void UploadExceptions(IEnumerable<ExceptionLogEntry> exceptions);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Прокси - класс инкапсулирует особенности работы
|
||
/// с WCF - инфраструктурой
|
||
/// </summary>
|
||
class LogSaverProxy : ILogSaver
|
||
{
|
||
/// <summary>
|
||
/// Подключение к службе
|
||
/// </summary>
|
||
class LogSaverClient : ClientBase<ILogSaver>
|
||
{
|
||
public ILogSaver LogSaver
|
||
{
|
||
get { return Channel; }
|
||
}
|
||
}
|
||
|
||
public void UploadExceptions(IEnumerable<ExceptionLogEntry> exceptions)
|
||
{
|
||
UseProxyClient(c => c.UploadExceptions(exceptions));
|
||
}
|
||
|
||
public void UploadLogEntries(IEnumerable<LogEntry> logEntries)
|
||
{
|
||
UseProxyClient(c => c.UploadLogEntries(logEntries));
|
||
}
|
||
|
||
private void UseProxyClient(Action<ILogSaver> accessor)
|
||
{
|
||
var client = new LogSaverClient();
|
||
try
|
||
{
|
||
accessor(client.LogSaver);
|
||
client.Close();
|
||
}
|
||
catch (CommunicationException e)
|
||
{
|
||
client.Abort();
|
||
Console.WriteLine(e.Message);
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Подход на основе делегатов может не только применяться для определения
|
||
* локальных действий внутри класса, но и передаваться извне другому объекту
|
||
* в аргументах конструктора.
|
||
*/
|
||
|
||
/*
|
||
* 2.2: Шаблонный метод на основе методов расширения
|
||
*/
|
||
|
||
public abstract class LogEntryBase
|
||
{
|
||
public DateTime EntryDateTime { get; internal set; }
|
||
public LogType Severity { get; internal set; }
|
||
public string? Message { get; internal set; }
|
||
|
||
/// <summary>
|
||
/// ExceptionLogEntry - будет возвращать информацию об исключении
|
||
/// </summary>
|
||
public string? AdditionalInformation { get; internal set; }
|
||
}
|
||
|
||
public static class LogEntryBaseEx
|
||
{
|
||
public static string GetText(this LogEntryBase logEntry)
|
||
{
|
||
var sb = new StringBuilder();
|
||
|
||
sb.AppendFormat("{0}", logEntry.EntryDateTime)
|
||
.AppendFormat("{0}", logEntry.Severity)
|
||
.AppendLine(logEntry.Message)
|
||
.AppendLine(logEntry.AdditionalInformation);
|
||
|
||
return sb.ToString();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Абстракция для взаимодействия с фабриками
|
||
/// </summary>
|
||
public abstract class Creator
|
||
{
|
||
private Product? product;
|
||
|
||
public abstract Product ProductFactoryMethod(int x, int y);
|
||
public abstract Product ProductFactoryMethod_2(int x, int y);
|
||
|
||
public void AnProductOperation(int x, int y)
|
||
{
|
||
product = ProductFactoryMethod(x, y);
|
||
}
|
||
|
||
public void AnProductOperation_2(int x, int y)
|
||
{
|
||
product = ProductFactoryMethod_2(x, y);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Конкретная фабрика
|
||
/// </summary>
|
||
public class ConcreteCreator : Creator
|
||
{
|
||
public override Product ProductFactoryMethod(int x, int y)
|
||
{
|
||
return new ConcreteProduct(x, y);
|
||
}
|
||
|
||
public override Product ProductFactoryMethod_2(int x, int y)
|
||
{
|
||
return new ConcreteProduct_2(x, y);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Абстракция для взаимодействия с продуктами
|
||
/// </summary>
|
||
public abstract class Product
|
||
{
|
||
public abstract void GetText();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Конкретный продукт
|
||
/// </summary>
|
||
public class ConcreteProduct : Product
|
||
{
|
||
public ConcreteProduct(int x, int y)
|
||
{
|
||
Console.WriteLine($"x {x} y {y}");
|
||
}
|
||
|
||
public override void GetText()
|
||
{
|
||
Console.WriteLine("1");
|
||
}
|
||
}
|
||
|
||
|
||
public class ConcreteProduct_2 : Product
|
||
{
|
||
public ConcreteProduct_2(int x, int y)
|
||
{
|
||
Console.WriteLine($"x2 {x} y2 {y}");
|
||
}
|
||
|
||
public override void GetText()
|
||
{
|
||
Console.WriteLine("2");
|
||
}
|
||
}
|
||
|
||
|
||
public class Program
|
||
{
|
||
public static void Main(string[] args)
|
||
{
|
||
Product product1 = null;
|
||
Product product2 = null;
|
||
var creator = new ConcreteCreator(); //Инициализирую фабрику
|
||
product1 = creator.ProductFactoryMethod(1, 2);
|
||
product2 = creator.ProductFactoryMethod_2(1, 2);
|
||
|
||
Console.WriteLine($"{product1.GetType().Name} {product2.GetType().Name}");
|
||
|
||
product1.GetText();
|
||
product2.GetText();
|
||
}
|
||
} |