Lab 4: The Command pattern
Objectives
1 But first...an introduction to Hourglass
2 Introduction
3 Provided code
4 What to do
4.1 Part 1:   Designing support for macros
4.2 Part 2:   Implement a macro
4.3 Part 3:   Enhancing the controller
4.4 Part 4:   More macros!
5 Questions to ponder/  discuss
8.9

Lab 4: The Command pattern

Starter files: code.zip

Objectives

The objectives of this lab are:

Make sure to submit your work for this lab by the end of the day.

1 But first...an introduction to Hourglass

Your midterms will be administered on Hourglass, a companion website to Handins that’s designed for taking exams. You will log in to https://hourglass.khoury.northeastern.edu during lab with your usual Handins login. Make sure you are using Chrome (or Chromium) or Firefox. You will have 20 minutes to complete a tutorial “exam” on Hourglass that will introduce you to the format and the various types of questions you might encounter during the real exam.

On the day of the real exam:

If you have a Mac with a camera-notch: You will need to configure your browser not to use that extra space. Follow these instructions to do so:

2 Introduction

The command design pattern offers a way to encapsulate extended functionality for an object. Specifically, each command object represents a unique way to use the existing set of operations of an object A to implement a new operation without changing the object A. As the new functionality is encapsulated within an object (the command object), adding newer operations is more scalable. Command objects also offer a way to enforce common functionality on all operations (such as undoing an operation).

Consider an object that offers a fixed set of functionality. A macro represents a unique sequence of using this functionality to implement a “meta operation”. Macros are supported in many programming languages as an efficient alternative to functions to create often-used meta functionality. Spreadsheet programs allow writing macros using existing functionality to create customized high-level operations. The advantage of a macro is that once written, it can be used as a “single function” just like any of the set functionality. In this way, macros are a scalable way to create a growing extended set of functionality.

In this lab, we would work with the spreadsheet program from the last lab, and add the ability to write macros on the spreadsheet.

3 Provided code

The provided code for this lab is almost identical to that of the last lab. The controller was also refactored to make this lab easier. You may choose to start with the provided code, or even the code that you created for the last lab.

Load the code in a new project in IntelliJ. Generate a class diagram for it to better understand its design (In IntelliJ Ultimate Edition, right-click on the src/ folder of the project, select Diagrams->Show Diagram->Java Classes.

The following is a brief summary of the provided code:

  1. SpreadSheet: interface that represents a spreadsheet.

  2. SparseSpreadSheet: a particular implementation of SpreadSheet.

  3. SpreadSheetController: the controller of an application that uses a spreadsheet.

  4. SpreadSheetProgram: a class defining the main method of this application.

4 What to do

For the purposes of this lab, we will assume that the SparseSpreadSheet has been tested and works correctly.

4.1 Part 1: Designing support for macros

One could write newer functions by repeatedly adding them to the Spreadsheet interface and the SparseSpreadSheet implementation. Alternatively one could create new interfaces that extend the Spreadsheet interface to add newer functions, and then implement them by reusing the SparseSpreadSheet class. Both of these approaches are not scalable/sustainable, because the number of newer functionality is endless.

Instead, we will make our spreadsheet support a macro. A macro will be given to the spreadsheet as a function object that operates on it. Thus, the spreadsheet needs to have only one additional functionality: the ability to accept macros as function objects.

  1. Create a new interface that represents a macro. Name it suitably. This is our “command” interface.

  2. Add a new method to this interface that takes in a Spreadsheet object and executes this macro on it.

  3. Extend the SpreadSheet interface in a new interface. Add a method that will accept an object of your macro interface and execute it on the spreadsheet.

  4. Implement this new interface and reuse the provided spreadsheet implementation in some way. Implement the new method you added above, so that the function object passed to it is executed on this spreadsheet.

The above steps create a new spreadsheet that, in addition to its original functionality, now accepts and runs any macro.

Confirm your design by showing the TA before moving on.

4.2 Part 2: Implement a macro

In last week’s lab, we implemented a new functionality: assign a specific value to an entire range of cells. In this lab, we will re-implement it using a macro.

  1. Implement the interface that represents your macro in a new class. This class represents the “bulk assign macro”. Name it suitably.

  2. Write a constructor that will take in the necessary arguments for this operation: the range of cells to set, and the value to set them to. The constructor should have the usual checks for invalid parameters.

  3. Write a test for this macro when provided valid inputs, as well as at least one test that verifies its intended behavior for invalid ranges of cells.

  4. Implement the required method in this class to set the range of specified cells in the spreadsheet passed to it, to the specified value.

Show your work to the TA before moving on.

4.3 Part 3: Enhancing the controller

In this part we will enhance the given controller so that it will also support the “bulk assign” operation as a script command. The syntax of this method will be bulk-assign-value from-row from-col-num to-row to-col-num value. The specified rows will still be in the letter format (i.e. ’A’, ’AA’, etc.).

  1. Write a new controller that extends the given controller.

  2. Write an equivalent constructor in the new controller that takes in the same parameters.

  3. Write a test for this controller that verifies that the script with the above syntax works correctly.

  4. Override the processCommand method. This method should check if the command given to it is “bulk-assign-value”. If so, then it should get the additional arguments, and use the macro object to execute this operation (what would you have to do to make sure this works?). Otherwise, it should delegate to the inherited processCommand method.

  5. Verify that the test you wrote above passes on your implementation.

  6. Override the printMenu method so that it includes this new command.

Show your test passing to the TA before moving on.

4.4 Part 4: More macros!

Now that we have a framework to add macros, we can extend the functionality more!

Write macros that will support the following script commands, using the same sequence as above.

Show the TA your work after implementing each macro.

5 Questions to ponder/discuss

Macros add extra functionality to the spreadsheet. But can we create macros that use other macros? In general, does the command design pattern support “meta commands”? How?

What are the limitations or drawbacks of your macro design (or in general, the command design pattern)? Try to identify specific problems that you may face now or in the future, rather than high-level limitations.