This presentation introduces the concept of a software framework and presents a particular framework for problem solving.

You will use and extend this framework in a number of upcoming labs and assignments that allow users to solve various problems.

A Java Archive (jar) file is similar to a zipped (compressed) folder of files whose purpose is to run a Java application on a client machine.

For this course, you will sometimes be asked to download and execute a particular jar file, for example, foo.jar.

Note: Depending on your browser, you may get a warning about downloading and executing files like this. In general, you may want to avoid downloading jar files from sources you do not trust.

In order to run a jar file on a machine:

This section presents some applications of the problem solving framework.

To see how they are used, refer to the Introductory Video (mp4) for this module.

The Farmer, Wolf, Goat, and Cabbage (FWGC) problem is depicted in the screenshot below.

The 8-Puzzle problem is depicted in the screenshot below.

The One-Way Streets problem is depicted in the screenshot below.

Frameworks often arise from the realization that separate program applications have similar structure.

For example, in the farmer, 8-puzzle, and one-way streets problems,

Examining three separate implementations of these problems would reveal much repeated code.

A framework manages repeated code so that it can be shared among multiple applications.

This section presents the types involved in a problem solving framework whose top-level package is called framework.

The current types involved include both abstract and concrete classes. Other types will be added as the framework is developed.

The types are further divided into these sub-packages:

Note that the code presented in this framework is generic in the sense that:

The framework.problem package contains the types relating directly to problem representation, apart from the issues of problem solution and interacting with the user.

These types are State, Mover, and Problem.

A central concept is that of a state of affairs of the problem being solved.

Since this concept is to range over widely differing application domains, we create an abstract class type called State. Extending classes will encapsulate the representation details of concrete problem states.

This type does not depend on any other type within the framework, so its UML model is simple and looks as shown below. The class code is shown in State.java.

The Mover class represents the moves in a problem solving domain.

A Mover object collects the available move names and associated functions that attempt to create new states as a result of making moves.

Since moves are applied to states, Mover depends on State, as shown below. The class code is shown in Mover.java.

Mover is made abstract so that it must be extended by classes that specify move names and functions by calling the addMove method.

The most important elements of the Mover class are the addMove and doMove methods.

addMove:

doMove:

The Problem class collects all the information required to solve a problem.

Getters and setters are provided for the problem name and introduction, the initial, current, and final States of the problem, and the problem's associated Mover object.

Since it stores various states and the mover object, Problem aggregates State and Mover objects, as shown below. The class code is shown in Problem.java.

The class is not abstract, but it can be subclassed, especially if the success method needs to be overridden.

Neither framework.problem nor framework.solution contains any code supporting user interaction. This is by design. Following the Model-View-Controller design pattern, we strictly separate code that represents a problem and its solution from code that provides a user interface.

The framework.ui package contains types relating to user interaction while solving problems.

Currently this package contains only one type, ProblemConsole, dedicated to interacting with users textually via a simulated terminal console.

Eventually we will add types to support GUI (graphical user interface) interaction.

The ProblemConsole class does all the work of interacting with the user and responding to attempts to make moves.

It extends the Console class (from previous exercises) and overrides its handleInput method to get move options from the user, check move legality, and update the display, which is entirely text-based, using strings.

A ProblemConsole object aggregates a single Problem object and a corresponding SolvingAssistant object, as shown below. The class code is shown in ProblemConsole.java.

The framework.solution package contains types relating to representing solutions to problems.

Currently this package contains only one type, SolvingAssistant, dedicated to supporting the process of users manually solving problems.

Eventually we will add types to support automatic problem solving.

The SolvingAssistant class provides support as moves are applied to solve a problem.

It tries moves, updates the current state as necessary, keeps track of the move count, and checks whether the problem has been solved.

These responsibilities require that SolvingAssistant contain a Problem object, as shown below. The class code is shown in SolvingAssistant.java.

A framework by itself is not an executable application. A framework user must provide code that "plugs in" to the framework code, resulting in something executable.

In Java, plugging into a framework involves implementing framework interfaces and extending framework classes.

This section provides an example of a dummy, though executable, application of the problem solving framework just described. Actual applications, like the FWGC and 8-Puzzle problems, are created in the same way.

An application of the problem solving framework requires at least four files. In the dummy application, these are:
A screenshot of the dummy application of the problem solving framework is shown to the right.

To see how it is used, refer to the Using Framework Video (mp4) for this module.

Although the application does not do much, it demonstrates the features of the framework:

The class diagram below shows how the application files fit into the framework.

The files for the dummy application are available on the menu to the left.

Note that the classes are in a package called domains.dummy.

DummyState (below) shows an example of state representation and the required overriding of the equals and toString methods.
The DummyMover class uses its parent's addMove method to add move names and their associated operations to the parent class's hash map:
The DummyProblem class simply uses its parent's setters to initialize the data (strings, states, and mover) required to represent the problem.
The DummyProblemTest class uses JavaFX to display a ProblemConsole that is wrapped around a DummyProblem, appropriately sized.

Since DummyProblemTest extends the JavaFX Application class, it can be run by executing its main method.

Running the DummyProblemTest class produces the application shown in the screen shot.