65.9K
CodeProject 正在变化。 阅读更多。
Home

装饰器模式变体

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (2投票s)

2009年7月26日

CPOL

2分钟阅读

viewsIcon

20042

装饰器模式的一个变体,以及扩展方法的使用。

引言

我们都听说过设计模式。它们是解决/改进常见开发场景的已知路径。模式可以修改和扩展以适应广泛的需求。

这里提供一个使用接口的装饰器模式变体。

背景

装饰器模式允许扩展无法继承或方法不可重写的类的行为。装饰器类持有对 sealed 类的引用,当调用装饰器类的方法时,它将执行其代码并调用引用的对象。结果是对 sealed 类的扩展。

使用代码

假设我们想要构建一个模块化的日志库,我们可以将装饰器模式调整到我们的需求。一个好的地方是,每个装饰器类都可以单独使用,也可以与其他装饰器堆叠使用。

这是所有装饰器之间的共享接口

using System;

namespace George.Decorator.ConsoleApp
{
    public interface ILoggingProvider
    {
        string Message {get;set;}
        string Source {get;set;}
        void Log();        
    }
}

现在是装饰器

控制台装饰器

using System;

namespace George.Decorator.ConsoleApp
{
    public class ConsoleDecorator : ILoggingProvider
    {
        private ILoggingProvider _iLoggingProvider = null;

        private string _message, _source = null;
        //empty contructor for a traditional object
        public ConsoleDecorator(){}
        
        //init class members and decorated interface
        public ConsoleDecorator(ILoggingProvider iLoggingProvider)
        {
                this._iLoggingProvider = iLoggingProvider;
                Message = iLoggingProvider.Message;
                Source = iLoggingProvider.Source;
        }
        
        //both current and decorated inteface method are invoked
        public void Log()
        {
            if(_iLoggingProvider != null)
            {
                WriteToConsole(_iLoggingProvider.Source, 
                               _iLoggingProvider.Message);
                _iLoggingProvider.Log();
            }
            else
            {
                WriteToConsole(Source,Message);
            }
            
        }
        
        private void WriteToConsole(string source, string message)
        {
            Console.WriteLine("--------------------------------");
            Console.WriteLine(string.Format("Source: {0}",source));
            Console.WriteLine(string.Format("Message: {0}",message));    
            Console.WriteLine("--------------------------------");
            Console.Write(Environment.NewLine);    
        }
        
        public string Message {
            get {
                return _message;                
            }
            set {
                _message = value;
            }
        }
        
        public string Source {
            get {
                return _source;
            }
            set {
                _source = value;
            }
        }
    }
}

事件日志装饰器

using System;
using System.Diagnostics;

namespace George.Decorator.ConsoleApp
{
    public class EventLogDecorator: ILoggingProvider
    {        
        private ILoggingProvider _iLoggingProvider = null;
        
        private string _message, _source = null;
        
        public EventLogDecorator(){}
        
        public EventLogDecorator(ILoggingProvider iLoggingProvider)
        {
            this._iLoggingProvider = iLoggingProvider;
            Message = iLoggingProvider.Message;
            Source = iLoggingProvider.Source;
        }
        
        public void Log()
        {
            if(_iLoggingProvider!=null)
            {
                CheckIfSourceExist(_iLoggingProvider.Source);
                EventLog.WriteEntry(_iLoggingProvider.Source, 
                                    _iLoggingProvider.Message);
                _iLoggingProvider.Log();
                
            }
            else
            {
                CheckIfSourceExist(Source);
                EventLog.WriteEntry(Source, Message);
            }                    
        }
        
        private void CheckIfSourceExist(string source)
        {
            if(!EventLog.SourceExists(source))
                EventLog.CreateEventSource(source, "Application");
        }
        
        public string Message {
            get {
                return _message;                
            }
            set {
                _message = value;
            }
        }
        
        public string Source {
            get {
                return _source;
            }
            set {
                _source = value;
            }
        }
    }
}

Winform装饰器

using System;
using System.Windows.Forms;


namespace George.Decorator.ConsoleApp
{
    public class WinFormDecorator: ILoggingProvider
    {
        private ILoggingProvider _iLoggingProvider = null;
        
        private string _message, _source = null;
        
        public WinFormDecorator(){}
        
        public WinFormDecorator(ILoggingProvider iLoggingProvider)
        {
            this._iLoggingProvider = iLoggingProvider;
            Message = iLoggingProvider.Message;
            Source = iLoggingProvider.Source;
        }
        
        public string Message {
            get {
                return _message;
            }
            set {
                _message = value;
            }
        }
        
        public string Source {
            get {
                return _source;
            }
            set {
                _source = value;
            }
        }
        
        public void Log()
        {
            if(_iLoggingProvider != null)
            {
                ShowMessageBox(_iLoggingProvider.Message, 
                               _iLoggingProvider.Source);
                _iLoggingProvider.Log();
            }
            else
            {
                ShowMessageBox(Message,Source);
            }
        }
        
        private void ShowMessageBox(string message, string source)
        {
            MessageBox.Show(message,source);
        }
    }
}

现在我们可以以独立模式使用装饰器对象

class Program
{
    public static void Main(string[] args)
    {
        ConsoleDecorator consoleDecorator = new ConsoleDecorator();
        EventLogDecorator eventLogDecorator = new EventLogDecorator();
        WinFormDecorator windowsFormDecorator = new WinFormDecorator();
        
        //in case of an information it will be enough the console windows
        
        consoleDecorator.Message = "Hi, here's the console";
        consoleDecorator.Source = "Console";
        consoleDecorator.Log();
        
        //if we want to log the message also on the eventviewer
        eventLogDecorator.Message = "Hi, here's the event viewer";
        eventLogDecorator.Source = "Event viewer";
        eventLogDecorator.Log();
        
        //or if we want to log the message also on the messagebox
        windowsFormDecorator.Message = "Hi, here's the windows form";
        windowsFormDecorator.Source = "Message Box";
        windowsFormDecorator.Log();

或者我们可以通过使用装饰器模式组合一个日志提供程序块

//decorator pattern variant
consoleDecorator = new ConsoleDecorator();
consoleDecorator.Message = "Hi, here's the console again";
consoleDecorator.Source = "Console";

eventLogDecorator = new EventLogDecorator(consoleDecorator);
windowsFormDecorator = new WinFormDecorator(eventLogDecorator);

//print out the output using all the providers
windowsFormDecorator.Log();

现在我们来看看为什么只有通过使用接口编程才能获得好处。在这种情况下,我们可以使用任何实现 ILoggingProvider 接口的对象来构建日志,而在其他情况下,例如使用扩展方法时

using System;
using System.Windows.Forms;
using System.Diagnostics;

namespace George.Decorator.ConsoleApp
{
    public static class ConsoleDecoratorExtensions
    {
        
        //Adding event viewer logging
        public static void LogWithEventViewer(this ILoggingProvider consoleDecorator)
        {
            if(!EventLog.SourceExists(consoleDecorator.Source))
                   EventLog.CreateEventSource(consoleDecorator.Source, "Application");
            EventLog.WriteEntry(consoleDecorator.Source,consoleDecorator.Message);
            consoleDecorator.Log();
        }
        
        //adding messagebox alert
        public static void LogWithMessageBox(this ConsoleDecorator consoleDecorator)
        {
             MessageBox.Show(consoleDecorator.Message,consoleDecorator.Source);
             consoleDecorator.Log();
        }
        
    }
}

接口的额外价值在于,现在我们有了适用于实现它的所有类的扩展方法,针对类的扩展方法将仅适用于该类。

//using extension methods
consoleDecorator.LogWithEventViewer();
consoleDecorator.LogWithMessageBox();

//interface extension method
windowsFormDecorator.LogWithEventViewer();

关注点

设计模式是一个引人入胜的话题,它们为解决日常问题提供了优雅的解决方案。在这种情况下,装饰器模式的一个变体有助于构建可以独立的对象(通常装饰器仅用于扩展对象),或者具有某种继承关系的对象。

© . All rights reserved.