94
Паттерн Декоратор (Decorator)

Паттерн Декоратор

  • Upload
    misha

  • View
    65

  • Download
    0

Embed Size (px)

DESCRIPTION

Паттерн Декоратор. (Decorator). Определение и мотивация Определение Декоратор — структурный шаблон проектирования, предназначенный для динамического подключения дополнительного поведения к объекту. Мотивация. Для динамического и прозрачного для клиентов добавления новых возможностей. - PowerPoint PPT Presentation

Citation preview

Slide 1

(Decorator)

, .

. , , , . - .

Component . , .

ConcreteComponent . , .

Decorator . Component .

ConcreteDecorator . .

, . , . . , . , .

. . , , . 1 . , :public interface IGlyph{void Draw();} 1 , :public abstract class GlyphDecorator : IGlyph{protected GlyphDecorator(IGlyph innerGlyph){Debug.Assert(innerGlyph != null);InnerGlyph = innerGlyph;}protected IGlyph InnerGlyph { get; set; }public virtual void Draw(){InnerGlyph.Draw();}} 1 , . : :public class BorderDecorator : GlyphDecorator {public BorderDecorator(IGlyph innerGlyph,Color borderColor, int borderWidth) : base(innerGlyph) {BorderColor = borderColor;BorderWidth = borderWidth;}public Color BorderColor { get; set; }public int BorderWidth { get; set; }public override void Draw() {DrawBorder();base.Draw();}} 1 , :IGlyph glyph = new BorderDecorator(new ImageGlyph("file"),Color.Red, 1);glyph.Draw(); ,, , , :IGlyph glyph = new BorderDecorator(new BorderDecorator(new ImageGlyph("file"), Color.Red, 1),Color.Black, 1);glyph.Draw(); 1 , . 2

xUnit.

ITest Run, . TestCase . TestSuite.

2 2 TestCase . , TestSuite. SetUp TearDown . 2 , (TestSuite) , TestCase:public class TestCase : ITest{public static ITest Suite(){TestSuite result = new TestSuite();foreach(MethodInfo method in GetTestMethods())result.AddTest(new TestCase(method));return result;}} 2 . , . :public class TestDecorator : ITest{private ITest test;public TestDecorator(ITest test) {this.test = test;}public virtual void Run() {test.Run();}} 2, :public class TestSetupDecorator : TestDecorator{public TestSetupDecorator(ITest test) : base(test) { }public virtual void SetUp() { }public virtual void TearDown() { }public override void Run(){SetUp();base.Run();TearDown();}} 3 : (Event Decorator). . , :public interface IConnection{void Connect();void Disconnect();void ExecuteQuery(string sql);} 3 :public class ConnectionDecorator : IConnection {private IConnection innerConnection;public ConnectionDecorator(IConnection innerConnection) {this.innerConnection = innerConnection;}public virtual void Connect() {innerConnection.Connect();}public virtual void Disconnect() {innerConnection.Disconnect();}public virtual void ExecuteQuery(string sql) {innerConnection.ExecuteQuery(sql);}} 3 :public class ConnectionEventDecorator : ConnectionDecorator{public ConnectionEventDecorator(IConnection innerConnection): base(innerConnection){ }public EventHandler BeforeConnect;public EventHandler AfterConnect;public override void Connect(){if (BeforeConnect != null)BeforeConnect(this, EventArgs.Empty);base.Connect();if (AfterConnect != null)AfterConnect(this, EventArgs.Empty);}} 4 , , GZipStream .NET:public class GZipStream : Stream{public GZipStream(Stream stream, CompressionMode compressionMode);public override int Read(byte[] array, int offset, int count);} 4private static void CreateFile() {Stream stream = new FileStream("text.gzip", FileMode.OpenOrCreate);stream = new GZipStream(stream, CompressionMode.Compress);using (stream) {using (StreamWriter writer = new StreamWriter(stream)) {writer.WriteLine("Bill Gates");writer.WriteLine("Linus Torvalds");}}}private static void ReadFile() {Stream stream = new FileStream("text.gzip", FileMode.Open);stream = new GZipStream(stream, CompressionMode.Decompress);using (stream) {using (StreamReader reader = new StreamReader(stream)) {while (!reader.EndOfStream)Console.WriteLine(reader.ReadLine());}}} 5 : . / .

5

5 (Command) , .

. . - . , . . Execute Command , , . Unexecute , Execute. . Command , . . , ().

Command . .

ConcreteCommand . - Receiver . Execute Receiver.

Client . ConcreteCommand

Invoker . .

Receiver . , . .

, , , , .

. , :, , .

. .

(). . 1 . , :public class Document{public string Text { get; set; }public int CursorPosition { get; set; }public string GetSelectedText();} 1 :public interface ICommand{void Execute();} 1 public class CopyCommand : ICommand{private readonly Document document;public CopyCommand(Document document){this.document = document;}public void Execute(){Clipboard.SetText(document.GetSelectedText());}} 1 :public class PasteCommand : ICommand{private readonly Document document;public PasteCommand(Document document){this.document = document;}public void Execute(){document.Text.Insert(document.CursorPosition, Clipboard.GetText());}} 1 :public class SaveCommand : ICommand{private readonly Document document;public SaveCommand(Document document){this.document = document;}public void Execute(){string fileName;if (ShowSaveFileDialog(out fileName)){File.WriteAllText(fileName, document.Text);}}} 1 :public MenuItem CreateCommandMenuItem(ICommand command, string caption){MenuItem result = new MenuItem();result.Click += delegate { command.Execute(); };result.Text = caption;return result;}public void BuildContextMenu(ContextMenu menu, Document document){PasteCommand pasteCommand = new PasteCommand(document);CompileCommand compileCommand = new CompileCommand(document);menu.MenuItems.Add(CreateCommandMenuItem(pasteCommand, "Paste"));menu.MenuItems.Add(CreateCommandMenuItem(compileCommand, "Compile"));} 1 . UnExecute. , . , IsReversible:public interface ICommand{void Execute();void UnExecute();bool IsReversible { get; }} 1 :public class CommandHistory{public void ExecuteCommand(ICommand command);public void Undo();public void Redo();} ExecuteCommand . Undo UnExecute . 1 :public class CommandHistory{private List commands = new List();public void ExecuteCommand(ICommand command){command.Execute();commands.Add(command);}} 1 . CurrentPosition. :public class CommandHistory {private List commands = new List();public int CurrentPosition { get; private set; }public void Undo() {Debug.Assert(CurrentPosition >= 0);commands[CurrentPosition].UnExecute();CurrentPosition--;}public void Redo() {Debug.Assert(CurrentPosition >= -1);Debug.Assert(CurrentPosition < commands.Count);CurrentPosition++;commands[CurrentPosition].Execute();}} 1 ,, :public class CommandHistory{private List commands = new List();public int CurrentPosition { get; private set; }public void ExecuteCommand(ICommand command){command.Execute();for (int i = commands.Count - 1; i > CurrentPosition; i--)commands.RemoveAt(i);commands.Add(command);CurrentPosition++;}} 2 . , .public class CompositeCommand : ICommand {private readonly List childCommands = new List();public CompositeCommand(params ICommand[] childCommands) {this.childCommands.AddRange(childCommands);}public void AddCommand(ICommand command) {childCommands.Add(command);}public void RemoveCommand(ICommand command) {childCommands.Remove(command);}} 2 :public class CompositeCommand : ICommand{private readonly List childCommands = new List();public void Execute(){foreach (ICommand childCommand in childCommands)childCommand.Execute();}public void UnExecute(){foreach (ICommand childCommand inchildCommands.AsEnumerable().Reverse())childCommand.UnExecute();}} 2 :public class CompositeCommand : ICommand {public void Execute() {List executedCommands = new List();foreach (ICommand childCommand in childCommands) {try {childCommand.Execute();executedCommands.Add(childCommand);}catch {foreach (ICommand executedCommand inexecutedCommands.AsEnumerable().Reverse())executedCommand.UnExecute();break;}}}} 2 , . :Document document = new Document();CompositeCommand compositeCommand = new CompositeCommand(new CreateBackupCommand(document),new CompileCommand(document));compositeCommand.Execute(); 3 WPF .NET .Windows Presentation Foundation (WPF) Windows. XAML XML . :http://msdn.microsoft.com/en-us/library/ms752059.aspxhttp://msdn.microsoft.com/en-us/library/ms754130.aspx 3 WPF :public interface ICommand{void Execute(object parameter);bool CanExecute(object parameter);event EventHandler CanExecuteChanged;} 3 :public class PasteCommand : ICommand {private readonly Document document;public PasteCommand(Document document) {this.document = document;}public void Execute(object parameter) {document.Text.Insert(document.CursorPosition, Clipboard.GetText());}public bool CanExecute(object parameter) {return Clipboard.ContainsText();}public event EventHandler CanExecuteChanged;} 3 . XAML , , :Paste, PasteCommand , DataContext . 4 Command . , -, . , -, -, , . 4

. :

class Divisor{int divisor;public:Divisor(int div): divisor(div) {}

int divide(int input) {return input / divisor;}int modulus(int input){return input % divisor;}}; 4 :class StringBuilder{string str;public:StringBuilder(string s): str(s) {}string prepend(string in) {return in + str;}string append(string in) {return str + in;}}; 4 :template class Command {public:typedef TArgument (TClass::*Action)(TArgument);private:TClass* object;Action method;TArgument argument;public:Command(TClass* o, Action m, TArgument a): object(o), method(m), argument(a){}TArgument execute() {return (object->*method)(argument);}}; 4

:

vector divisorCommands;

divisorCommands.push_back(&Divisor::divide,16));Command(&Divisor(3),divisorCommands.push_back(&Divisor::modulus, 16));Command(&Divisor(3),divisorCommands.push_back(&Divisor::divide,16));Command(&Divisor(4),divisorCommands.push_back(Command(&Divisor(4),&Divisor::modulus, 16));for (int i = 0; i < 4; i++)cout 0) {result.AppendString("WHERE", " ");result.AppendString(whereCondition.ToString(), " ");}return result.ToString();}} 2 Oracle 8 AddJoin :public class Oracle8SelectQueryBuilder : SelectQueryBuilder{public override void AddJoin(string tableName,string leftSide, string rightSide, JoinKind joinKind){AddSourceTable(tableName);if (joinKind == JoinKind.LeftOuter)AddWhereCondition(string.Format("{0} = {1} (+)",leftSide, rightSide));else if (joinKind == JoinKind.RightOuter)AddWhereCondition(string.Format("{0} (+) = {1}",leftSide, rightSide));elseAddWhereCondition(string.Format("{0} = {1}",leftSide, rightSide));}} 2 , :private static void BuildQuery(SelectQueryBuilder queryBuilder){queryBuilder.AddFieldName("employee.first_name", "employee_first_name");queryBuilder.AddFieldName("employee.last_name", "employee_first_name");queryBuilder.AddFieldName("country.id", "country_id");queryBuilder.AddFieldName("country.name", "country_name");queryBuilder.AddSourceTable("employee");queryBuilder.AddJoin("country","country.id", "employee.country_id", JoinKind.LeftOuter);} 2 :SelectQueryBuilder queryBuilder = new SelectQueryBuilder();BuildQuery(queryBuilder);Console.WriteLine(queryBuilder.GetSql());SELECTemployee.first_name AS employee_first_name,employee.last_name AS employee_first_name,country.id AS country_id,country.name AS country_nameFROM employeeLEFT OUTER JOIN country ONcountry.id = employee.country_id : 2 :SelectQueryBuilder queryBuilder = new Oracle8SelectQueryBuilder();BuildQuery(queryBuilder);Console.WriteLine(queryBuilder.GetSql());SELECTemployee.first_name AS employee_first_name,employee.last_name AS employee_first_name,country.id AS country_id,country.name AS country_nameFROM employee, countryWHEREcountry.id = employee.country_id (+) :