ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • OOP Design Pattern - Behavioral Pattern 1
    프로그래밍 언어 2024. 10. 14. 22:28

    Chain of Responsibility

    Chain-of-Responsibility Pattern

    • A behavioral design pattern consisting of a source of command objects and a series of processing objects
    • Each processing object contains logic that defines the types of command objects that it can handle
      • The rest are passed to the next processing object in the chain
      • A mechanism exists for adding new processing objects to the end of this chain
    • Variation : act as dispatchers, capable of sending commands out in a variety of directions, forming a tree of responsibility
      • Can occur recursively, with processing objects calling higher-up processing objects
      • Recursion continues until the command is prcessed, or the entire tree has been explored

     

    Overview

    • Solves problem like:
      • Coupling the sender of a request to its receiver should be avoided
      • It should be possible that more than one receiver can handle a request
    • Describes how to solve such problems:
      • Define a chain of receiver objects having the responsiblity, depending on run-time conditions, to either handle a request or forward it to the next receiver on the chain (if any)

    Class UML of Chain-of-Responsibility pattern

     

    Example

    [Flags]
    public enum LogLevel
    {
        None = 0,                //      0
        Info = 1,                //      1
        Debug = 2,               //     10
        Warning = 4,             //    100
        Error = 8,               //   1000
        FunctionalMessage = 16,  //  10000
        FunctionalError = 32,    // 100000
        All = 63                 // 111111
    }
    
    // Abstract Handler in chain of responsibility pattern.
    public abstract class Logger
    {
        protected LogLevel logMask;
        protected Logger next; // The next handler in the chain
        
        public Logger(LogLevel mask) { this.logMask = mask; }
        
        // Sets the next logger to make a list / chain of handlers.
        public Logger SetNext(Logger nextLogger)
        {
            Logger lastLogger = this;
            
            while (lastLogger.next != null)
            {
                lastLogger = lastLogger.next;
            }
            
            lastLogger.next = nextLogger;
            
            return this;
        }
        
        public void Message(string msg, LogLevel severity)
        {
            // Tru only if any of the logMask bits are set in severity
            if ((severity & logMask) != 0) WriteMessage(msg);
            
            if (next != null) next.Message(msg, severity);
        }
        
        protected abstract void WriteMessage(string msg);
    }
    
    public class ConsoleLogger : Logger
    {
        public ConsoleLogger(LogLevel mask) : base(mask) { }
        
        protected override void WriteMessage(string msg)
        {
            Console.WriteLine("Writing to console : " + msg);
        }
    }
    
    public class EmailLogger : Logger
    {
        public EmailLogger(LogLevel mask) : base(mask) { }
        
        protected override void WriteMessage(string msg)
        {
            // Placeholder for mail send logic, usually the email configurations are saved in config file.
            Console.WriteLine("Sending via email : " + msg);
        }
    }
    
    public class FileLogger : Logger
    {
        public FileLogger(LogLevel mask) : base(mask) { }
        
        protected override void WriteMessage(string msg)
        {
            Console.WriteLine("Writing to log file : " + msg);
        }
    }
    
    public class Program
    {
        public static void Main(string[] args)
        {
            // Build the chain of responsibility
            Logger logger = new ConsoleLogger(LogLevel.All)
                .SetNext(new EmailLogger(LogLevel.FunctionalMessage | LogLevel.FunctionalError))
                .SetNext(new FileLogger(LogLevel.Warning | LogLevel.Error));
                
            // Handled by ConsoleLogger since the console has a loglevel of all
            logger.Message("Entering function ProcessOrder().", LogLevel.Debug);
            logger.Message("Order record retrieved.", LogLevel.Info);
    
            // Handled by ConsoleLogger and FileLogger since filelogger implements Warning & Error
            logger.Message("Customer Address details missing in Branch DataBase.", LogLevel.Warning);
            logger.Message("Customer Address details missing in Organization DataBase.", LogLevel.Error);
    
            // Handled by ConsoleLogger and EmailLogger as it implements functional error
            logger.Message("Unable to Process Order ORD1 Dated D1 For Customer C1.", LogLevel.FunctionalError);
    
            // Handled by ConsoleLogger and EmailLogger
            logger.Message("Order Dispatched.", LogLevel.FunctionalMessage);
        }
    }

     

    Command

    Command Pattern

    • A behavioral design pattern in which an object is used to encapsulate all information needed to perform an action or trigger an event at a later time
    • The information includes the method name, the object that owns the method and values for the method parameters
    • Command
      • Knows about receiver and invokes a method of the receiver
      • Values for parameters of the receiver method are stored in the command
    • Receiver
      • The object to execute methods
      • Stored in the command object by aggregation
      • Works when the execute() method in command is called
    • Invoker
      • Knows how to execute a command, and optionally does bookkeeping about the command execution
      • Does not know anything about a concrete command
      • Knows only about the command interface
    • Client : decides which command to execute at which points

     

    Overview

    • Solves problem like:
      • Coupling the invoker of a request to a particular request should be avoided
      • It should be possible to configure an object (that invokes a request) with a request
    • Describes how to solve such problem:
      • Define separate (command) objects that encapsulate a request
      • A class delegates a request to a command object instead of implementing a particular request directly

    Class UML of command pattern

     

    Example

    public interface Command 
    {
        public void Execute();
    }
    
    public class CommandFire : Command
    {
        public void Execute() 
        {
            Fire();
        }
        
        public void Fire() 
        {
            Console.WriteLine("Fire");
        }
    }
    
    public class CommandJump : Command
    {
        public void Execute() 
        {
            Jump();
        }
        
        public void Jump() 
        {
            Console.WriteLine("Jump");
        }
    }
    
    public class CommandRoll : Command
    {
        public void Execute() 
        {
            Roll();
        }
        
        public void Roll() 
        {
            Console.WriteLine("Roll");
        }
    }

     

    Interpreter

    Interpreter Pattern

    • Specifies how to evaluate sentences in a language
    • Have a class for each symbol in a specialized computer language

     

    Overview

    • Solves problem like:
      • A grammar for a simple language should be defined so that sentences in the language can be interpreted
    • Describes how to solve such problems:
      • Define a grammar for a simple language by defining a Expression class hierarchy and implementing an interpret() operation
      • Represent a sentence in the language by an abstract syntax tree (AST) made up of Expression instances
      • Interpret a sentence by calling interpret() on the AST

    Class UML of interpreter pattern

     

    Example

    using System;
    using System.Collection.Generic;
    
    namespace OOP;
    
    public class Context
    {
        public Stack<string> Result = new Stack<string>();
    }
    
    public interface IExpression
    {
        public void Interpret(Context context);
    }
    
    public abstract class OperatorExpression : IExpression
    {
        public IExpression Left { set; private get; }
        public IExpression Right { set; private get; }
        
        public void Interpret(Context context)
        {
            Left.Interpret(context);
            string leftValue = context.Result.Pop();
            
            Right.Interpret(context);
            string rightValue = context.Result.Pop();
            
            DoInterpret(context, leftValue, rightValue);
        }
        
        protected abstract void DoInterpret(Context context, string leftValue, string rightValue);
    }
    
    public class EqualsExpression : OperatorExpression
    {
        protected override void DoInterpret(Context context, string leftValue, string rightValue)
        {
            context.Result.Push(leftValue == rightValue ? "true" : "false");
        }
    }
    
    public class OrExpression : OperatorExpression
    {
        protected override void DoInterpret(Context context, string leftValue, string rightValue)
        {
            context.Result.Push(leftValue == "true" || rightValue == "true" ? "true" : "false");
        }
    }
    
    public class MyExpression : IExpression
    {
        public string Value { private get; set; }
    
        public void Interpret(Context context)
        {
            context.Result.Push(Value);
        }
    }
    
    public class Program
    {
        public static void Main()
        {
            var context = new Context();
            var input = new MyExpression();
            
            var expression = new OrExpression
            {
                Left = new EqualsExpression
                {
                    Left = input,
                    Right = new MyExpression { Value = "4" }
                },
                Right = new EqualsExpression
                {
                    Left = input,
                    Right = new MyExpression { Value = "four" }
                }
            };
            
            input.Value = "four";
            expression.Interpret(context); // Output : "true"
            Console.WriteLine(context.Result.Pop());
            
            input.Value = "44";
            expression.Interpret(context); // Output : "false"
            Console.WriteLine(context.Result.Pop());
        }
    }
Designed by Tistory.