During this lab session:
This activity helps the student develop the following skills, values and attitudes: ability to analyze and synthesize, capacity for identifying and solving problems, and efficient use of computer systems.
This lab is based on chapters 6 and 7 of [FREEMAN]. It can be developed individually or in pairs.
The following ZIP file contains the files and folders you'll be needing for this lab: command_adapter.zip. Any new files you create must go inside the corresponding folder.
We have the following source code for a blender class:
namespace Headfirst.Command.Undo { public class Blender { int speed = 0; public int CurrentSpeed() { return speed; } public string NewSpeed(int speed) { if (0 <= speed && speed <= 10) { this.speed = speed; } if (speed == 0) { return "Blender OFF"; } else { return string.Format("Blender ON speed = {0}", speed); } } } }
We want to be able to use instances of this class through a remote control with undoable capabilities. In order to do this, you must write the following new classes:
Headfirst.Command.Undo.BlenderIncreaseSpeedCommand
Headfirst.Command.Undo.BlenderOffCommand
Make sure that they behave exactly as expected by the following unit test. Do not modify any other part of the code.
namespace Headfirst.Command.Undo { using System; using NUnit.Framework; [TestFixture] public class TestCommand { static readonly string EOL = Environment.NewLine; [Test] public void TestBlender() { var remoteControl = new RemoteControlWithUndo(); var blender = new Blender(); var increaseCommand = new BlenderIncreaseSpeedCommand(blender); var offCommand = new BlenderOffCommand(blender); remoteControl.SetCommand(0, increaseCommand, offCommand); Assert.AreEqual("Blender ON speed = 1", remoteControl.OnButtonWasPushed(0)); Assert.AreEqual("Blender OFF", remoteControl.OffButtonWasPushed(0)); Assert.AreEqual("Blender ON speed = 1", remoteControl.UndoButtonWasPushed()); Assert.AreEqual("Blender ON speed = 2", remoteControl.OnButtonWasPushed(0)); Assert.AreEqual( "------ Remote Control -------" + EOL + "[slot 0] BlenderIncreaseSpeedCommand BlenderOffCommand" + EOL + "[slot 1] NoCommand NoCommand" + EOL + "[slot 2] NoCommand NoCommand" + EOL + "[slot 3] NoCommand NoCommand" + EOL + "[slot 4] NoCommand NoCommand" + EOL + "[slot 5] NoCommand NoCommand" + EOL + "[slot 6] NoCommand NoCommand" + EOL + "[undo] BlenderIncreaseSpeedCommand" + EOL, remoteControl.ToString()); Assert.AreEqual("Blender ON speed = 3", remoteControl.OnButtonWasPushed(0)); Assert.AreEqual("Blender ON speed = 4", remoteControl.OnButtonWasPushed(0)); Assert.AreEqual("Blender ON speed = 3", remoteControl.UndoButtonWasPushed()); Assert.AreEqual("Blender ON speed = 4", remoteControl.OnButtonWasPushed(0)); Assert.AreEqual("Blender ON speed = 5", remoteControl.OnButtonWasPushed(0)); Assert.AreEqual("Blender ON speed = 6", remoteControl.OnButtonWasPushed(0)); Assert.AreEqual("Blender OFF", remoteControl.OffButtonWasPushed(0)); Assert.AreEqual("Blender ON speed = 6", remoteControl.UndoButtonWasPushed()); Assert.AreEqual( "------ Remote Control -------" + EOL + "[slot 0] BlenderIncreaseSpeedCommand BlenderOffCommand" + EOL + "[slot 1] NoCommand NoCommand" + EOL + "[slot 2] NoCommand NoCommand" + EOL + "[slot 3] NoCommand NoCommand" + EOL + "[slot 4] NoCommand NoCommand" + EOL + "[slot 5] NoCommand NoCommand" + EOL + "[slot 6] NoCommand NoCommand" + EOL + "[undo] BlenderOffCommand" + EOL, remoteControl.ToString()); } } }
The ZIP file contains inside the chapter07
folder a
dynamic link library called Stack.dll
which
includes the definition of the Headfirst.Adapter.Stack<T>
generic class. A stack is a data structure that follows a LIFO
(last in, first out) policy. It's public interface is described
in the following table:
Name | Description |
---|---|
bool IsEmpty
|
Property that returns true if the current
stack instance is empty, or false
otherwise.
|
int Count
|
Property that returns the number of elements actually stored in the current stack instance. |
void Push(T value)
|
Method that inserts value at the top of the
current stack instance.
|
T Pop()
|
Method that removes and returns the element at the top
of the current stack instance. Throws a
System.InvalidOperationException if called
on an empty stack.
|
You are also given the following interface definition for a generic queue type:
namespace Headfirst.Adapter { public interface IQueue<T> { bool IsEmpty { get; } int Count { get; } void Insert(T value); T Remove(); } }
A queue is a data structure that follows a FIFO (first in,
first out) policy. The Insert
method adds an
element at the end of the current queue. Remove
removes and returns the element at the front of the current
queue, or throws an exception if the queue is empty. The
IsEmpty
and Count
properties work
like their stack counterparts.
Write a class called Headfirst.Adapter.StackishQueue<T>
that adapts a stack so that it can be used as a queue. Make sure
it behaves exactly as expected by the following unit tests.
namespace Headfirst.Adapter { using System; using NUnit.Framework; [TestFixture] public class TestAdapter { [Test] public void TestStackishQueueOfInts() { Stack<int> s = new Stack<int>(); IQueue<int> q = new StackishQueue<int>(s); Assert.IsTrue(s.IsEmpty); Assert.IsTrue(q.IsEmpty); q.Insert(0); q.Insert(1); q.Insert(2); q.Insert(3); Assert.IsFalse(s.IsEmpty); Assert.IsFalse(q.IsEmpty); Assert.AreEqual(4, s.Count); Assert.AreEqual(4, q.Count); Assert.AreEqual(0, q.Remove()); Assert.AreEqual(1, q.Remove()); Assert.AreEqual(2, q.Remove()); Assert.AreEqual(3, q.Remove()); Assert.IsTrue(s.IsEmpty); Assert.IsTrue(q.IsEmpty); Assert.AreEqual(0, s.Count); Assert.AreEqual(0, q.Count); try { q.Remove(); Assert.Fail(); } catch (InvalidOperationException e) { Assert.AreEqual("You can't remove from an empty queue!", e.Message); } } [Test] public void TestStackishQueueOfStrings() { Stack<string> s = new Stack<string>(); IQueue<string> q = new StackishQueue<string>(s); Assert.IsTrue(s.IsEmpty); Assert.IsTrue(q.IsEmpty); q.Insert("Frodo"); q.Insert("Gandalf"); q.Insert("Legolas"); Assert.IsFalse(s.IsEmpty); Assert.IsFalse(q.IsEmpty); Assert.AreEqual(3, s.Count); Assert.AreEqual(3, q.Count); Assert.AreEqual("Frodo", q.Remove()); Assert.AreEqual("Gandalf", q.Remove()); Assert.AreEqual(1, s.Count); Assert.AreEqual(1, q.Count); Assert.AreEqual("Legolas", q.Remove()); Assert.IsTrue(s.IsEmpty); Assert.IsTrue(q.IsEmpty); Assert.AreEqual(0, s.Count); Assert.AreEqual(0, q.Count); try { q.Remove(); Assert.Fail(); } catch (InvalidOperationException e) { Assert.AreEqual("You can't remove from an empty queue!", e.Message); } } } }
To hand in your lab work, follow these instructions:
readme.txt
text file that includes the name
and student ID of the authors. Copy this file to both
chapter06
and chapter07
folders.
chapter06
and chapter07
directories.
Call this file chapter06_07.zip
.
This activity will be evaluated using the following criteria:
100 | The code works as requested. |
---|---|
60-90 | The code works, but has some flaws. |
20-50 | The code doesn't work, but it seams that some amount of time was spent on it. |
DA | The program was plagiarized. |