Showing posts with label Refactoring. Show all posts
Showing posts with label Refactoring. Show all posts

Wednesday, November 27, 2013

Refactoring to Command design pattern

Hello

Example inspired by Russian language explanation of [DesignPattern] Command
Native Russian speakers can see the good video on YouTube

So, the example is about remote control for home stuff, like TV, MP3 player, Lights etc. We assume, that these devices have only on/off states

So, lets design RC for Light, MP3 and video electrical devices

RC will be looks like box with 6 buttons:

  • Light on
  • Light off
  • MP3 on
  • MP3 off
  • Video on
  • Video off
Lets code it!


namespace RemoteControlDP
{
    public class RemoteControl
    {
        public void DrawMenu()
        {
            Console.WriteLine("Select operation:");
            Console.WriteLine("1\t on light");
            Console.WriteLine("1 off\t off light");
            Console.WriteLine("2\t on tv");
            Console.WriteLine("2 off\t off tv");
            Console.WriteLine("3\t on mp3");
            Console.WriteLine("3 off\t off mp3");
        }

        public enum ProductState { On, Off }

        public void PerformAction()
        {
            string userSelected = Console.ReadLine();

            switch (userSelected)
            {
                case "1":
                    LightOn();
                    break;
                case "1 off":
                    LightOff();
                    break;
                case "2":
                    TVOn();
                    break;
                case "2 off":
                    TVOff();
                    break;
                case "3":
                    MP3On();
                    break;
                case "3 off":
                    MP3Off();
                    break;
            }
        }

        private static void MP3Off()
        {
            Console.WriteLine("MP3 is off");
        }

        private static void MP3On()
        {
            Console.WriteLine("MP3 is on");
        }

        private static void TVOff()
        {
            Console.WriteLine("TV is off");
        }

        private static void TVOn()
        {
            Console.WriteLine("TV is on");
        }

        private static void LightOff()
        {
            Console.WriteLine("Light is off");
        }

        private static void LightOn()
        {
            Console.WriteLine("Light is on");
        }
    }
}

Client code:
namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            RemoteControl remote = new RemoteControl();
            string userInput = string.Empty;

            do
            {
                remote.DrawMenu();
                remote.PerformAction();

                Console.WriteLine("To continue select y");
                userInput = Console.ReadLine();
            }
            while (userInput.Equals("y"));
        }
    }
}

UML class Diagram lol:


Very good, until comes one of 3 inevitable things: Change Requirements

Client wish command on Fan!
So, lets rock. Class RemoteControl gonna be opened, changed, added etc. Bad smell!
After client wish add Radio, printer, PC etc.

Lets encapsulate changes and use some smart thing, was invented by 4 smart humans. Lets refactor to Command Design Pattern : "Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations".

Big picture: i wish create structure of classes and its relationships, so i can create programs and assign to buttons in real-time. Looks fine! It is like programmable Logitech remote control:
which can be programmed in real time and commands will be assigned to buttons! A little difference, SW we do in our self, no need to pay for it :-)

First part: create commands which do On operation (Off operation will be described in second part):

ICommand interface. There only one method:
namespace RemoteControlDP
{
    public interface ICommand
    {
        void Execute();
    }
}

Light, MP3 and Video implementations. Each implementation also have overriding of ToString. We will see use of it in RemoteControl class.

using System;

namespace RemoteControlDP
{
    public class LightCommand : ICommand
    {
        public void Execute()
        {
            Console.WriteLine("Light is on");
        }

        public override string ToString()
        {
            return "on Light";
        }
    }
}

using System;

namespace RemoteControlDP
{
    public class MP3Command : ICommand
    {
        public void Execute()
        {
            Console.WriteLine("MP3 is on");
        }

        public override string ToString()
        {
            return "on MP3";
        }
    }
}

using System;

namespace RemoteControlDP
{
    public class TVCommand : ICommand
    {
        public void Execute()
        {
            Console.WriteLine("TV is on");
        }

        public override string ToString()
        {
            return "on TV";
        }
    }
}

RemoteControl refactored:
using System;
using System.Collections.Generic;

namespace RemoteControlDP
{
    public class RemoteControl
    {
        Dictionary<string, ICommand> _commands;

        public RemoteControl()
        {
            _commands = new Dictionary<string, ICommand>();
        }

        public void SetCommand(string button, ICommand cmd)
        {
            _commands[button] = cmd;
        }

        public void DrawMenu()
        {
            Console.WriteLine("Select operation:");

            foreach (String btn in _commands.Keys)
            {
                Console.WriteLine("{0} \t - {1}", btn, _commands[btn].ToString());
            }
        }

        public void PerformAction()
        {
            string userSelected = Console.ReadLine() ?? String.Empty;

            if (_commands.ContainsKey(userSelected))
            {
                _commands[userSelected].Execute();
            }
        }
    }
}

RemoteControl explained:
  • Collection. There collection of assigned commands per buttons. Class have no idea about command. It is incapsulated.
  • SetCommand. Ability assign buttons to commands from outside. From client, for a true.
  • DrawMenu. There no need long list of strings, only calling to overridden ToString method in ICommand  implementations.
  • PerformAction. Just call to Execute method of ICommand  implementations.
Client slightly changed:
namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            RemoteControl remote = new RemoteControl();
            string userInput = string.Empty;
   
            remote.SetCommand("1", new LightCommand());
            remote.SetCommand("2", new TVCommand());
            remote.SetCommand("3", new MP3Command());
            
            do
            {
                remote.DrawMenu();
                remote.PerformAction();

                Console.WriteLine("To continue select y");
                userInput = Console.ReadLine();
            }
            while (userInput.Equals("y"));
        }
    }
}
There using of assign command to buttons in real-time.

So, if we need add Fan, we only create Fan class, implement ICommand and add it to remote, using SetCommand.

UML class diagram:


UML Sequence diagram:
Lets see GOF class diagram (taken from http://www.dofactory.com):
Client - is same as our client
Invoker - is RemoteControl
Command - is ICommand
ConcreteCommand - is Light/MP3/TV command
Receiver - will be added later

Lets continue refactoring to GOF pattern.

I wish add Receiver class. Is real implementation of devices. Its includes its state too.
My recievers called LightReceiver, MP3Receiver, TVReceiver.
namespace RemoteControlDP
{
    public enum ReceiverState { On, Off, }
}

using System;

namespace RemoteControlDP
{
    public class TVReceiver
    {
        public void TurnOn()
        {
            DeviceState = ReceiverState.On;
            Console.WriteLine("TV is {0}", DeviceState);
        }

        public ReceiverState DeviceState { get; private set; }
    }
}

using System;

namespace RemoteControlDP
{
    public class MP3Receiver
    {
        public void TurnOn()
        {
            DeviceState = ReceiverState.On;
            Console.WriteLine("MP3 is {0}", DeviceState);
        }

        public ReceiverState DeviceState { get; private set; }
    }
}

See 2 kinds of lights: Color and somple light:
using System;

namespace RemoteControlDP
{
    public abstract class LightReceiver
    {
        public virtual void TurnOn()
        {
            DeviceState = ReceiverState.On;
            Console.WriteLine("Light is {0}", DeviceState);
        }

        public ReceiverState DeviceState { get; private set; }
    }

    public class ColorLightReceiver : LightReceiver
    {
        public override void TurnOn()
        {
            base.TurnOn();
            Console.WriteLine("Red Color");
        }
    }
}

using System;

namespace RemoteControlDP
{
    public class FanReceiver
    {
        public void TurnOn()
        {
            DeviceState = ReceiverState.On;
            Console.WriteLine("Fan is {0}", DeviceState);
        }

        public ReceiverState DeviceState { get; private set; }
    }
}

Commands changed too:
This class will contain injected Recievers realisation and have method Action
Receiver for Light can be injected as different Lights implementations, so it makes system more flexible.

using System;

namespace RemoteControlDP
{
    public class FanCommand : ICommand
    {
        private FanReceiver _fan;

        public FanCommand(FanReceiver fan)
        {
            _fan = fan;
        }

        public void Execute()
        {
            _fan.TurnOn();
        }

        public override string ToString()
        {
            return "on Fan";
        }
    }
}

using System;

namespace RemoteControlDP
{
    public class LightCommand : ICommand
    {
        private LightReceiver _light;

        public LightCommand(LightReceiver light)
        {
            _light = light;
        }

        public void Execute()
        {
            _light.TurnOn();
        }

        public override string ToString()
        {
            return "on Light";
        }
    }
}

using System;

namespace RemoteControlDP
{
    public class MP3Command : ICommand
    {
        private MP3Receiver _mp3;

        public MP3Command(MP3Receiver mp3)
        {
            _mp3 = mp3;
        }

        public void Execute()
        {
            _mp3.TurnOn();
        }

        public override string ToString()
        {
            return "on MP3";
        }
    }
}

using System;

namespace RemoteControlDP
{
    public class TVCommand : ICommand
    {
        private TVReceiver _tv;

        public TVCommand(TVReceiver tv)
        {
            _tv = tv;
        }

        public void Execute()
        {
            _tv.TurnOn();
        }

        public override string ToString()
        {
            return "on TV";
        }
    }
}

Client changed too:
namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            RemoteControl remote = new RemoteControl();
            string userInput = string.Empty;
   
            remote.SetCommand("1", new LightCommand(new ColorLightReceiver()));
            remote.SetCommand("2", new TVCommand(new TVReceiver()));
            remote.SetCommand("3", new MP3Command(new MP3Receiver()));
            remote.SetCommand("4", new FanCommand(new FanReceiver()));
            
            do
            {
                remote.DrawMenu();
                remote.PerformAction();

                Console.WriteLine("To continue select y");
                userInput = Console.ReadLine();
            }
            while (userInput.Equals("y"));
        }
    }
}
You can see, Light command injected by Color light. It can be injected by other implementation of light.

Now, our design is looks like GOF design.

Class diagram:


We can stop here, but Command design pattern by GOF "...and support undoable operations."
Later i will cover it, or try it yourself.

that's it


en → ru
Expl

Sunday, November 10, 2013

Observer design pattern from Real World

Hello
Observer design pattern well described here: WIKI: Observer pattern

I wish give some real example.

So, example...
My example is: GUI for creating controls + share information between:

My UI is very simple: 2 buttons + text box:

Add listener button, which create UserControl and subscribe it
Remove listener: remove UserControl and detach it
Text box: when it updates, each UserControl get informed about new text

UserControl:
Lable: show Subject status
TextBox: can be updated, so updated text goes to Subject and from Subject to each Observer:

And, if i wish talk with pictures:

Start app:

Add listener:


Add 1 more listener:

Now, main UI set text ("hello") in its textbox, so each listener get it ("hello") and show in own lable:

And, 1-st listener can set its text ("mama") in its textbox:
and we see, "mama" is updated for each listener


Now, main UI set new text ("papa") in its textbox, so each listener get it ("papa") and show in own lable:

Code

Solution:

IObserver.cs:
namespace ObserverFormDP
{
    public interface IObserver
    {
        void StateUpdate();
    }
}

ISubject.cs:
using System;

namespace ObserverFormDP
{
    public interface ISubject
    {
        String State { get; set; }
        void Attach(IObserver obsever);
        void Detach(IObserver obsever);
        void Notify();
    }
}

Subject.cs:
using System.Collections.Generic;

namespace ObserverFormDP
{
    public class Subject : ISubject
    {
        private string _state;
        private List<IObserver> _attachedObservers;

        public Subject()
        {
            _attachedObservers = new List<IObserver>();
        }

        public void Attach(IObserver obsever)
        {
            _attachedObservers.Add(obsever);
        }

        public void Detach(IObserver obsever)
        {
            _attachedObservers.Remove(obsever);
        }

        public void Notify()
        {
            foreach (IObserver o in _attachedObservers)
            {
                o.StateUpdate();
            }
        }

        public string State
        {
            get
            {
                return _state;
            }
            set
            {
                _state = value;
                Notify();
            }
        }
    }
}

UserControl1:
using System.Windows.Forms;

namespace ObserverFormDP
{
    public partial class UserControl1 : UserControl, IObserver
    {
        private ISubject _subject;

        public UserControl1(ISubject subject)
        {
            InitializeComponent();

            _subject = subject;
        }

        public void StateUpdate()
        {
            label1.Text = _subject.State;
        }

        private void textBox1_TextChanged(object sender, System.EventArgs e)
        {
            _subject.State = textBox1.Text;
        }
    }
}

Form1:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace ObserverFormDP
{
    public partial class Form1 : Form
    {
        List<IObserver> _observers;
        ISubject _subject;

        public Form1()
        {
            InitializeComponent();
            _observers = new List<IObserver>();
            _subject = new Subject();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            UserControl1 uc1 = new UserControl1(_subject);
            _observers.Add(uc1);
            _subject.Attach(uc1);
            uc1.Location = new Point(_observers.Count * 110, 20);
            Controls.Add(uc1);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (_observers.Count == 0) return;
            IObserver o = _observers[_observers.Count - 1];
            Controls.Remove(o as UserControl);
            _observers.Remove(o);
            _subject.Attach(o);
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            _subject.State = textBox1.Text;
        }
    }
}

Thats all

Thanks,
Efim

Thursday, November 7, 2013

Refactoring classes to Strategy and State design patterns

Hi,
Today i try use 2 behavioral design pattern: Strategy and State design patterns. About this patterns there a lot of stuff in net. I wish try use some refactoring, for moving poor designed class to better designed, by using Strategy and State design patterns.

In my example i do calculations of taxes for products depend on season. For example, in Summer, tax for product, which costs 100 units not same, as a tax in Winter for product, which costs 150 units. So, there is system of tax calculation, depends on season and product price.

Lets design!

Bang!

namespace SeasonTaxesNoDP

{
    public class SeasonTaxes
    {
        public enum Season { Spring, Summer, Autumn, Winter, }

        Season _season;

        public SeasonTaxes()
        {
            _season = Season.Spring;
        }

        public void NextSeason()
        {
            switch (_season)
            {
                case Season.Autumn:
                    _season = Season.Winter;
                    break;
                case Season.Spring:
                    _season = Season.Summer;
                    break;
                case Season.Summer:
                    _season = Season.Autumn;
                    break;
                case Season.Winter:
                    _season = Season.Spring;
                    break;
            }
        }

        public void PreviousSeason()
        {
            switch (_season)
            {
                case Season.Autumn:
                    _season = Season.Summer;
                    break;
                case Season.Spring:
                    _season = Season.Winter;
                    break;
                case Season.Summer:
                    _season = Season.Spring;
                    break;
                case Season.Winter:
                    _season = Season.Autumn;
                    break;
            }
        }

        public double CalculateTax(double productPrice)
        {
            switch (_season)
            {
                case Season.Autumn:
                    if (productPrice > 180)
                    {
                        return productPrice * 0.32 + 11.2;
                    }
                    else
                    {
                        return productPrice * 0.32 + 13.2;
                    }
                case Season.Spring:
                    if (productPrice > 170)
                    {
                        return productPrice * 0.52 + 15.2;
                    }
                    else
                    {
                        return productPrice * 0.42 + 17.2;
                    }
                case Season.Summer:
                    if (productPrice > 300)
                    {
                        return productPrice * 0.72 + 21.2;
                    }
                    else
                    {
                        return productPrice * 0.42 + 23.2;
                    }
                case Season.Winter:
                    if (productPrice > 220)
                    {
                        return productPrice * 0.342 + 11.2;
                    }
                    else
                    {
                        return productPrice * 0.562 + 16.2;
                    }
            }
            return 0.0;
        }
    }
}

Using:
        private static void f4()
        {
            SeasonTaxesNoDP.SeasonTaxes season = new SeasonTaxesNoDP.SeasonTaxes();
            season.CalculateTax(345);

            season.NextSeason();
            season.CalculateTax(567);
        }

SeasonTaxes is an Finite-state machine (FSM) of seasons + system of calculations, so it do 2 things. So it have 2 axis of changes: if there change system of calculations it will change or if there change in FSM it will change too. So, it violates The Single Responsibility Principle (SRP).

This code is hard to understand and hard to maintenance.

If i will add new season, it will violate Open - Close principle (OCP)
If i will remove season, same.
Same about system of calculations.

Lets do refactoring.
I will move to State design pattern, so i wish move the FSM out from the class. It will remove one axis of potential changes: changes in Seasons switch machine


Code:
namespace SeasonTaxesStateDP
{
    public abstract class SeasonState
    {
        public abstract void NextSeason(SeasonTaxes seasonTaxes);
        public abstract void PreviousSeason(SeasonTaxes seasonTaxes);
        public abstract double CalculateTax(double productPrice);
    }

    public class SpringSeasonState : SeasonState
    {
        public override void NextSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new SummerSeasonState(); }
        public override void PreviousSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new WinterSeasonState(); }

        public override double CalculateTax(double productPrice)
        {
            if (productPrice > 170)
            {
                return productPrice * 0.52 + 15.2;
            }
            else
            {
                return productPrice * 0.42 + 17.2;
            }
        }
    }

    public class AutumnSeasonState : SeasonState
    {
        public override void NextSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new WinterSeasonState(); }
        public override void PreviousSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new SummerSeasonState(); }

        public override double CalculateTax(double productPrice)
        {
            if (productPrice > 180)
            {
                return productPrice * 0.32 + 11.2;
            }
            else
            {
                return productPrice * 0.32 + 13.2;
            }
        }
    }

    public class SummerSeasonState : SeasonState
    {
        public override void NextSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new AutumnSeasonState(); }
        public override void PreviousSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new SpringSeasonState(); }

        public override double CalculateTax(double productPrice)
        {
            if (productPrice > 300)
            {
                return productPrice * 0.72 + 21.2;
            }
            else
            {
                return productPrice * 0.42 + 23.2;
            }
        }
    }

    public class WinterSeasonState : SeasonState
    {
        public override void NextSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new SpringSeasonState(); }
        public override void PreviousSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new AutumnSeasonState(); }

        public override double CalculateTax(double productPrice)
        {
            if (productPrice > 220)
            {
                return productPrice * 0.342 + 11.2;
            }
            else
            {
                return productPrice * 0.562 + 16.2;
            }
        }
    }

    public class SeasonTaxes
    {
        public SeasonState State { get; set; }

        public SeasonTaxes()
        {
            State = new SpringSeasonState();
        }

        public void NextSeason()
        {
            State.NextSeason(this);
        }

        public void PreviousSeason()
        {
            State.PreviousSeason(this);
        }

        public double CalculateTax(double productPrice)
        {
            return State.CalculateTax(productPrice);
        }
    }
}


Class SeasonTaxes get smaller and simpler. It is delegates responsibilities to SeasonState implementations. 
But, each implementation of SeasonState  violates OCP and SRP. 

So, i did not like calculations in State classes. 
It is looks, like a mess.
I wish move tax calculations out from FSM.
Lets do refactoring to Strategy design pattern:


Code:
namespace SeasonTaxesStateStrategyDP
{
    public interface IStrategyTax
    {
        double CalculateTax(double productPrice);
    }

    public class SpringStrategyTax : IStrategyTax
    {
        public double CalculateTax(double productPrice)
        {
            if (productPrice > 170)
            {
                return productPrice * 0.52 + 15.2;
            }
            else
            {
                return productPrice * 0.42 + 17.2;
            }
        }
    }

    public class AutumnStrategyTax : IStrategyTax
    {
        public double CalculateTax(double productPrice)
        {
            if (productPrice > 180)
            {
                return productPrice * 0.32 + 11.2;
            }
            else
            {
                return productPrice * 0.32 + 13.2;
            }
        }
    }

    public class SummerStrategyTax : IStrategyTax
    {
        public double CalculateTax(double productPrice)
        {
            if (productPrice > 300)
            {
                return productPrice * 0.72 + 21.2;
            }
            else
            {
                return productPrice * 0.42 + 23.2;
            }
        }
    }

    public class WinterStrategyTax : IStrategyTax
    {
        public double CalculateTax(double productPrice)
        {
            if (productPrice > 220)
            {
                return productPrice * 0.342 + 11.2;
            }
            else
            {
                return productPrice * 0.562 + 16.2;
            }
        }
    }

    public abstract class SeasonState
    {
        public abstract void NextSeason(SeasonTaxes seasonTaxes);
        public abstract void PreviousSeason(SeasonTaxes seasonTaxes);

        protected IStrategyTax _strategyTax;

        public double CalculateTax(double productPrice)
        {
            return _strategyTax.CalculateTax(productPrice);
        }
    }

    public class SpringSeasonState : SeasonState
    {
        public override void NextSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new SummerSeasonState(); }
        public override void PreviousSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new WinterSeasonState(); }
    }

    public class AutumnSeasonState : SeasonState
    {
        public override void NextSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new WinterSeasonState(); }
        public override void PreviousSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new SummerSeasonState(); }
    }

    public class SummerSeasonState : SeasonState
    {
        public override void NextSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new AutumnSeasonState(); }
        public override void PreviousSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new SpringSeasonState(); }
    }

    public class WinterSeasonState : SeasonState
    {
        public override void NextSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new SpringSeasonState(); }
        public override void PreviousSeason(SeasonTaxes seasonTaxes) { seasonTaxes.State = new AutumnSeasonState(); }
    }

    public class SeasonTaxes
    {
        public SeasonState State { get; set; }

        public SeasonTaxes()
        {
            State = new SpringSeasonState();
        }

        public void NextSeason()
        {
            State.NextSeason(this);
        }

        public void PreviousSeason()
        {
            State.PreviousSeason(this);
        }

        public double CalculateTax(double productPrice)
        {
            return State.CalculateTax(productPrice);
        }
    }
}

that's it