Strategy Pattern
Challenge You are working on a Gaming application. The player can select between two different guns: 1. Pistol having 5 bullets 2. Grenade Launcher having 20 bullets In the normal coding scenario, if the gamer changes the gun we have to do lot of if conditions in the fire method, in the draw gun method, in the bullet animation methods. How to do a better approach? Definition GoF Definition: "Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it" Implementation We can avoid the above complications by switching to the Strategy pattern. Our solution would be: Extract the difference implementations into appropriate classes and switch between the classes. Code Explained The core classes involved are: . Gamer . PistolGun implementing IGun . GrenadeLauncher implementing IGun Whenever the user changes the gun the Gamer.Gun property is switched between PistolGun and GrenadeLauncher instances. Here the IGun interface extracts the part which differs for different guns. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; namespace StrategyPattern.Strategy { public class Gamer { private Label _bulletsLabel; public Gamer(Label bulletsLabel) { _bulletsLabel = bulletsLabel; } private IGun _gun; public IGun Gun { get { return _gun; } set { _gun = value ; RefreshGunInfo(); } } private void RefreshGunInfo() { _gun.Draw(); ShowBulletsInfo(); } private void ShowBulletsInfo() { _bulletsLabel.Text = "Bullets: " _gun.Bullets.ToString(); } public void Fire() { _gun.Fire(); ShowBulletsInfo(); } } } ************************************************** using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace StrategyPattern.Strategy { public class GrenadeLauncherGun : IGun { public GrenadeLauncherGun(PictureBox gunBox, PictureBox bulletBox) { _gunBox = gunBox; _bulletBox = bulletBox; } public void Fire() { if (_bullets == 0) { MessageBox.Show("No Ammo!" ); return; } _bulletBox.Image = Images.Grenade; _bulletBox.Left = _gunBox.Left _gunBox.Width 5; _bulletBox.Top = _gunBox.Top 60; _bulletBox.Show(); for (int i = 1; i <= 18; i ) { Thread.Sleep(50); Application.DoEvents(); _bulletBox.Left = _bulletBox.Width / 2; } _bullets--; _bulletBox.Hide(); } public void Draw() { _gunBox.Image = Images.GrenadeLauncher; _gunBox.Width = _gunBox.Image.Width; _gunBox.Height = _gunBox.Image.Height; } public int _bullets = 20; public int Bullets { get { return _bullets; } set { _bullets = value; } } private PictureBox _gunBox; private PictureBox _bulletBox; public PictureBox GunBox { get { return _gunBox; } set { _gunBox = value; } } public PictureBox BulletBox { get { return _bulletBox; } set { _bulletBox = value; } } } } ***************************************************** using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; namespace StrategyPattern.Strategy { public interface IGun { void Fire(); void Draw(); int Bullets { get ; set; } PictureBox GunBox { get ; set; } PictureBox BulletBox { get ; set; } } } ************************************************ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace StrategyPattern.Strategy { public class PistolGun : IGun { public PistolGun(PictureBox gunBox, PictureBox bulletBox) { _gunBox = gunBox; _bulletBox = bulletBox; } public void Fire() { if (_bullets == 0) { MessageBox.Show("No Ammo!" ); return; } _bulletBox.Image = Images.Bullet; _bulletBox.Left = _gunBox.Left _gunBox.Width 5; _bulletBox.Top = _gunBox.Top 1; _bulletBox.Show(); for (int i = 1; i <= 20; i ) { Thread.Sleep(50); Application.DoEvents(); _bulletBox.Left = _bulletBox.Width / 2; } _bullets--; _bulletBox.Hide(); } public int _bullets = 5; public int Bullets { get { return _bullets; } set { _bullets = value; } } public void Draw() { _gunBox.Image = Images.Pistol; _gunBox.Width = _gunBox.Image.Width; _gunBox.Height = _gunBox.Image.Height; } private PictureBox _gunBox; private PictureBox _bulletBox; public PictureBox GunBox { get { return _gunBox; } set { _gunBox = value; } } public PictureBox BulletBox { get { return _bulletBox; } set { _bulletBox = value; } } } } ***************************************************** using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using StrategyPattern.Strategy; namespace StrategyPattern { public partial class MainForm : Form { private Gamer _gamer; private IList <IGun> _gunList = new List <IGun>(); private int _index; public MainForm() { InitializeComponent(); _gunList.Add( new PistolGun (GunBox, BulletBox)); _gunList.Add( new GrenadeLauncherGun (GunBox, BulletBox)); _gamer = new Gamer (BulletsLabel); _gamer.Gun = _gunList[_index = 0]; } private void ChangeGun_Click(object sender, EventArgs e) { _index ; if (_index >= _gunList.Count) _index = 0; _gamer.Gun = _gunList[_index]; } private void button2_Click(object sender, EventArgs e) { _gamer.Fire(); } } }
Comments