440 likes | 564 Views
Chapter 7 : Building a Text-based user interface. Objectives. After studying this chapter you should understand the following: independence of servers from clients; likeliness of the user interface to change; i/o streams; structure of a simple text-based user interface;
E N D
Objectives • After studying this chapter you should understand the following: • independence of servers from clients; • likeliness of the user interface to change; • i/o streams; • structure of a simple text-based user interface; • purpose and structure of a while loop; • how existing classes can be composed to define a new class. Chapter 7
Objectives • Also, you should be able to: • use input/output objects to read and write data; • build a simple text-based user interface; • use and trace a basic while statement; • define classes whose implementations contain other classes as components. Chapter 7
Relating User-interface and Model • Model: objects that solve problem at hand. • User interface: interacts with user, getting input from user, and giving output to user, reporting on status of model. • Flexibility in design: identifying these as separate subsystems. Chapter 7
Stream-based I/O • Data streams: sequence of bytes. • character stream: sequence of characters • input stream: stream is a source of data for an application. • output stream: stream is appliction destination (or sink). Chapter 7
Standard Input and Output streams standard output: characters to display Chapter 7
Writing standard output • System.out: provides methods for writing to standard output. public void println (String s) Write specified String to standard output and then terminate the line. public void print (String s) Write the specified String to standard output. public void println () Terminate current line by writing line terminator to standard output. publicvoid flush () Flush stream: write buffered output to standard output and flush that stream. Chapter 7
Input: nhUtilities.basicIO.BasicFileReader • Constructors: public BasicFileReader () Create a BasicFileReader attached to standard input. public BasicFileReader (String fileName) Create a BasicFileReader attached to the named file. Chapter 7
Input: nhUtilities.basicIO.BasicFileReader • Command: publicvoid readInt () Read a new int from input stream. The digit string is interpreted as a decimal integer. Characters following any white space in input stream must have format of an optionally signed decimal integer. Chapter 7
readInt BasicFileReader standard input lastInt = ? ¿ • • • • 1 2 3 4 5 a b c Application before executing readInt() BasicFileReader standard input lastInt = 12345 ¿ a b c Application after executing readInt() Chapter 7
Input: nhUtilities.basicIO.BasicFileReader • Query: publicint lastInt () int most recently read by readInt. require: this.readInt() has been successfully performed. Chapter 7
Input: nhUtilities.basicIO.BasicFileReader • Other commands for reading from the input stream: • readDouble and readWord skip white space at beginning of stream. • readDouble requires characters after white space have format of an optionally signed double literal. • readWord reads a sequence of nonwhite space characters. public void readChar () Read a new character from this input stream. public void readDouble () Read a new double from this input stream. public void readLine () Read the rest of the line from this input stream. publicvoid readWord () Read a new word from this input stream. Chapter 7
Input: nhUtilities.basicIO.BasicFileReader • Other queries: publicchar lastChar () Character most recently read by readChar. require: this.readChar() has been successfully performed. public double lastDouble () double most recently read by readDouble. require: this.readDouble() has been successfully performed. publicString lastString () String most recently read by readWord or readLine. require: this.readWord() or this.readLine() has been successfully performed. Chapter 7
Input: nhUtilities.basicIO.BasicFileReader • Other queries: publicboolean eof () End of input stream has been reached. Chapter 7
Building an interface for Rectangle • Build an interface that let’s user specify dimensions of the Rectangle and ask for property to be displayed. classRectangleTUI A simple text-based interface for Rectangles. public RectangleTUI () Create a new RectangleTUI instance. publicvoid start () Run the interface. Chapter 7
Building an interface for Rectangle • Application creates interface and executes start: publicclass RectangleExample { publicstaticvoidmain (String[] argv) { (new RectangleTUI()).start(); } } Chapter 7
Building an interface for Rectangle • RectangleTUI properties: • Instance variables are initialized in constructor: private Rectangle rectangle; // the model private BasicFileReader in; //standard input public RectangleTUI () { this.rectangle = null; this.in = new BasicFileReader(); } Chapter 7
Building an interface for Rectangle privatevoid createRectangle () Create a new Rectangle with user-provided dimensions. Uses readIntWithPromptto get dimensions from user. • To get Rectangle dimensions from user: private int readIntWithPrompt (String prompt) { System.out.print(prompt); System.out.flush(); in.readInt(); in.readLine(); return in.lastInt(); } Chapter 7
Building an interface for Rectangle private void createRectangle () { int length; int width; length = readIntWithPrompt( "Rectangle length (a non-negative integer): "); width = readIntWithPrompt( "Rectangle width (a non-negative integer): "); this.rectangle = new Rectangle(length,width); } Chapter 7
Building an interface for Rectangle • RectangleTUI is a client of Rectangle. • Constructor creates an instance of Rectangle using input values from user. • But, Rectangle has pre-conditions to keep: public Rectangle (int length, int width) Create a new Rectangle with specified length and width. require: length >= 0 && width >= 0 • User may enter negative values for length or width. Chapter 7
B E G I N true condition false statement E N D While statement while ( condition ) statement Chapter 7
Re-implementing createRectangle private void createRectangle () { //initialize to insure at least one execution of loops: int length = -1; int width = -1; while (length < 0) length = readIntWithPrompt( "Rectangle length (a non-negative integer): "); while (width < 0) width = readIntWithPrompt( "Rectangle width (a non-negative integer): "); // assert: length >=0 && width >= 0 this.rectangle = new Rectangle(length,width); } Chapter 7
Building an interface for Rectangle privatevoid displayMenu () Display the menu to the user. privatevoid executeChoice (int choice) Perform the indicated action, and display results to the user. Chapter 7
Building an interface for Rectangle • Name operation choices with identifiers: privatestaticfinalint LENGTH = 1; private static final int WIDTH = 2; private static final int AREA = 3; private static final int PERIMETER = 4; private static final int NEW = 5; private static final int EXIT = 0; private static final int NO_CHOICE = -1; Chapter 7
Building an interface for Rectangle publicvoid start () { createRectangle(); int choice = NO_CHOICE; while (choice!= EXIT) { displayMenu(); choice= readIntWithPrompt("Enter choice: "); executeChoice(choice); } } Chapter 7
Building an interface for Rectangle private void displayMenu () { System.out.println(); System.out.println("Enter number denoting action to perform:"); System.out.println("Display length............." + LENGTH); System.out.println("Display width.............." + WIDTH); System.out.println("Display area..............." + AREA); System.out.println("Display perimeter.........." + PERIMETER); System.out.println("Create new rectangle......." + NEW); System.out.println("Exit......................." + EXIT); } Chapter 7
Building an interface for Rectangle private void executeChoice (int choice) { System.out.println(); if (choice == LENGTH) System.out.println("Length is " + rectangle.length()); else if (choice == WIDTH) System.out.println("Width is " + rectangle.width()); else if (choice == AREA) System.out.println("Area is " + rectangle.area()); else if (choice == PERIMETER) System.out.println("Perimeter is " + rectangle.perimeter()); else if (choice == NEW) createRectangle(); else if (choice == EXIT) System.out.println("Goodbye."); else System.out.println(choice + " is not valid."); } Chapter 7
Using composition • Build an application that lets a user access a “locked oracle.” • user can get a fortune from oracle only by providing correct key. • Use classes CombinationLock and Oracle. • Create two new classes, • one modeling a locked oracle, and • other defining user interface. Chapter 7
Using composition public class Oracle A dispenser of fortunes. An Oracle gives a fortune only if it is awake; normal sequence of actions is: wake Oracle; get fortune; put the Oracle back to sleep. public Oracle ()Create new Oracle. This Oracle is initially asleep.ensure: !this.isAwake() public boolean isAwake ()This Oracle is awake. public String fortune () The prophecy currently seen by this Oracle.require: this.isAwake() publicvoid awaken ()Wake this Oracle. Oracle will divine a fortune when it wakes. public void sleep ()Put this Oracle to sleep. Chapter 7
Using composition publicclass LockedOracle A keyed dispenser of fortunes. A LockedOracle will give a fortune only if the correct key is provided. A LockedOracle must be told to conjure a fortune before the fortune can be retrieved. public static final String NO_FORTUNE String indicating no fortune has been conjured. public LockedOracle (intkey) Create new LockedOracle with the specified key.require: 0 <= key && key <= 999 public String fortune () The prophecy currently seen by this LockedOracle. If a fortune has not been conjured, the StringNO_FORTUNE is returned. publicvoid conjureFortune (int keyToTry) Prophesy. This LockedOracle will make a prophecy only if the correct key is presented.require: 0 <= keyToTry && keyToTry <= 999 Chapter 7
Using composition • Composition: process of defining a new class by putting together existing classes. • An instance of the new class, the composite, references instances of the existing classes, its components. Chapter 7
Implementing LockedOracle • LockedOracle class defined to be a composite, with CombinationLock and Oracle components. Chapter 7
Implementing LockedOracle private CombinationLock lock; private Oracle oracle; private String fortune; //current prophesy publicstaticfinal String NO_FORTUNE = "Sorry, no fortune for you."; • Instance variables are initialized in constructor: public LockedOracle (int key) { lock = new CombinationLock(key); lock.close(); oracle = new Oracle(); fortune = NO_FORTUNE; } Chapter 7
Implementing LockedOracle public String fortune () { return this.fortune; } • Command conjureFortune first attempts to open lock, and wakes oracle only if it succeeds: public void conjureFortune (int keyToTry) { lock.open(keyToTry); if (lock.isOpen()) { oracle.awaken(); fortune = oracle.fortune(); oracle.sleep(); lock.close(); } else fortune = NO_FORTUNE; } Chapter 7
Implementing the User interface class LockedOracleTUI A simple text-based interface for a LockedOracle. public LockedOracleTUI (LockedOracle oracle) Create a new interface for the specified LockedOracle. publicvoid start () Run the interface. Chapter 7
Implementing the User interface • Application creates an oracle and an interface, and executes interface’s start method: publicclass OracleExample { public static void main (String[] argv) {LockedOracle oracle = new LockedOracle(123); LockedOracleTUI ui = new LockedOracleTUI(oracle); ui.start() } } Chapter 7
Implementing the User interface • Instance variables and constructor. private LockedOracle oracle; private BasicFileReader in; public LockedOracleTUI (LockedOracle oracle) { this.oracle = oracle; this.in = new BasicFileReader(); } Chapter 7
Implementing the User interface • Specify private helper methods: privateboolean readYes (String prompt) Read a yes or no response from the user. Return true if user keys “yes.” privateint readKey (String prompt) Read and return a legal key. ensure: 0 <= this.readKey() && this.readKey() <= 999 Chapter 7
Implementing the User interface public void start () { String fortune; boolean goOn = true; while (goOn) { goOn = readYes("Fortune? (Key yes or no): "); if (goOn) { int key = readKey("Enter key (0-999): "); oracle.conjureFortune(key); fortune = oracle.fortune(); System.out.println(fortune); System.out.println(); } } System.out.println("Good-bye."); } Chapter 7
Summary • Built a simple text-based user interface. • We reviewed the relationship between client and server: • a client is dependent on its server, • a server is independent of its client. Chapter 7
Summary • In designing a system, it is preferable to make stable components independent of those likely to require change. • Since user interface is considerably less stable than model, we favor designs in which the user interface acts as client to the model. • In cases where model must collaborate with the user interface, need to minimize interface for this collaboration. Chapter 7
Summary • Introduced i/o streams. • A stream is a sequence of bytes, sometimes viewed as characters, to which an application can append data (an output stream) or from which an application can read data (an input stream). • Java has an extensive library of classes to deal with streams. • Use only basic functionality • from the predefined object System.out for output, • BasicFileReader class from nhUtilities.basicIO package for input. Chapter 7
Summary • Presented two simple applications with their text-based user interfaces. • Introduced while statement or while-loop: a Java construct that specifies a sequence of actions to be repeated until a condition fails to hold. Chapter 7
Summary • In design of LockedOracle composed existing classes to construct a new class. • The relation between a composite class and its component classes is called the has-a relation. • LockedOracle class wraps Oracle, adapting its specification to that required by the system: the adapter pattern. Chapter 7