280 likes | 621 Views
CS242 Advanced Programming Concepts in Java 11/06/07 Serialization Observer Design Pattern Prof. Searleman jets@clarkson.edu Outline Cloning (Cloneable Interface) Serialization (Serializable Interface) Observer Design Pattern: examples HW#5 posted, due: 11/13/07
E N D
CS242Advanced Programming Concepts in Java 11/06/07 Serialization Observer Design Pattern Prof. Searleman jets@clarkson.edu
Outline • Cloning (Cloneable Interface) • Serialization (Serializable Interface) • Observer Design Pattern: examples HW#5 posted, due: 11/13/07 hint: useScanner (orStringTokenizer) also: do a screen capture of your GUI and turn it in Exam#2 Tues, Nov 27, 7:00 pm, SC 362 practice problems
Cloning – It is up to the class designer to determine whether: • the default clone() is good enough: “Shallow cloning” • the default clone() can be patched up by calling clone on each non-primitive, mutable instance variable: “Deep cloning” • give up – don’t use clone
Copy Constructor A copy constructor for class X is of the form: public X( X copy ) i.e. the constructor has one argument which is an object of type X itself // Example: Copy constructor for class Swimmer public Swimmer(Swimmer obj) { this.name = obj.name; this.swimTime = obj.swimTime; this.eventDate = (Date) obj.eventDate.clone(); // Date is cloneable }
Swimmer String Kristen name cu1 swimTime 26.31 eventDate Date year 2007 etc. Suppose you want to save swimmer data on a file, and restore it later. How can this be accomplished? 1. Save each component separately in a file; To restore, read in the data and reconstruct each part 2. Serialize it
Object Serialization • Any object that implements the serializable interface can be converted into a sequence of bytes • Implements “lightweight persistence”; persistance – object’s lifetime is independent of program execution (lives even when the program terminates) • Serializable interface – no methods, just tagging
Serializable Interface To write a serializable object: • Create an OutputStream of some flavor, wrap it inside an ObjectOutputStream • Call writeObject() – the object will be serialized and sent to the output stream To read (restore) a serializable object: Similar to the above, but call readObject() to “deserialize” the object (remember to cast)
public class Swimmer implements Cloneable, Serializable { private String name; private float swimTime; private Date eventDate; // methods } Consider the swimmer class. When it is serialized, it will also serialize all the object fields as well (String & Date)
ObjectOutputStream outstrm = new ObjectOutputStream( new FileOutputStream(“swimmers.dat”); // cu1 refers to a swimmer outstrm.writeObject(cu1); outstrm.close();
// later, read in the swimmer data ObjectInputStream instrm = new ObjectInputStream( new FileInputStream(“swimmers.dat”); Swimmer s1 = (Swimmer) instrm.readObject();
Writing serializable objects To write an object of a given class • The class must be public • The class must implement Serializable • If the base class is not Serializable, then it must have a default constructor
public class Swimmer implements Serializable // ObjectOutputStream objOUT opened Swimmer[] team = { new Swimmer(…), new Swimmer(…), … new Swimmer(…) ); try { for (int i = 0; i < team.length; i++) objOUT.writeObject(team[i]); objOUT.close() } catch // exceptions
ObjectInputStream objIN // opened Swimmer obj = null; int count = 0; try { while (true) { // rewrite to terminate when EOS obj = (Swimmer) objIN.readObject(); count++; // add obj to a List } objOUT.close(); // convert the list to an array } catch // exceptions
Recap: Observer Design Pattern • key idea: minimize the coupling between the model, views and controllers • a controller detects user interaction that changes the data • that controller must tell model about the change • the model must notify all views of that change • all views must repaint() themselves • during painting, each view asks the model for the current data to display model – only knows that views exist and they need to be notified views – don’t know anything about the controllers (so easy to add more views to a model) controller – easy to change the controller for a view
from http://www.javaworld.com http://www.javaworld.com/javaworld/jw-03-2003/jw-0328-designpatterns.html?
Observer: Method #1 Write your own interfaces for Observer& Subject public interface Observer { /** notify Observers that a change has occurred */ public void sendNotify(String s); } public interface Subject { /** register your interest in the subject */ public void registerInterest(Observer obs); }
public class Watch2Windows extends WindowFrame implements ActionListener, ItemListener, Subject { private List observers; private ColorFrame cframe; private ListFrame lframe; //------------------------------------------ public Watch2Windows() { observers = new ArrayList(); //observing frames //---------create observers--------- cframe = new ColorFrame(this); lframe = new ListFrame(this); }
public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) notifyObservers((JRadioButton)e.getSource()); } private void notifyObservers(JRadioButton rad) { String color = rad.getText(); for (int i=0; i< observers.size(); i++) { ((Observer)(observers.get(i))).sendNotify(color); } } public void registerInterest(Observer obs) { observers.add(obs); //adds observer to list }
public class ColorFrame extends JFrame implements Observer{ public ColorFrame( Subject s) { super(“Color View”); s.registerInterest(this); } public void sendNotify(String s){ color_name = s; if (s.equalsIgnoreCase("RED")) color = Color.red; if (s.equalsIgnoreCase("BLUE")) color = Color.blue; if (s.equalsIgnoreCase("GREEN")) color = Color.green; setBackground(color); } }
public class ListFrame extends JFrame implements Observer{ private JList list; private JListData listData; public ListFrame( Subject s) { super(“List View”); s.registerInterest(this); listData = new JListData(); // the list model list = new JList(listData); // the visual list } public void sendNotify(String s){ listData.addElement(s); } }
Observer: Method #2 Use the java.util.Observer interface and the java.util.Observable class /** any class can implement this interface to be an observer */ public interface Observer { /** application calls notifyObservers() which automatically calls this method for each registered observer */ public void update(Observable o, Object arg); }
Observer: Method #2 (cont.) /** represents an “observable” object, aka subject or model*/ public class Observable extends Object { // void addObserver(Observer o) // void deleteObserver(Observer o) // int countObservers() // boolean hasChanged() // protected void setChanged() // protected void clearChanged() /** if data has changed (as indicated by setChanged), then notify all observers and then clearChanged */ void notifyObservers(); }
// Account is an Observable class that represents a bank // account in which funds may be deposited or withdrawn. package com.deitel.account; import java.util.Observable; public class Account extends Observable // subject { // set Account balance and notify observers of change private void setBalance( double accountBalance ) { balance = accountBalance; // must call setChanged before notifyObservers // to indicate model has changed setChanged(); // notify Observers that model has changed notifyObservers(); }
public abstract class AbstractAccountView extends JPanel implements Observer { // observer public AbstractAccountView(Account observableAccount ) throws NullPointerException { // register as an Observer to receive account updates observableAccount.addObserver( this ); } // receive updates from Observable Account public void update( Observable observable, Object object ){ updateDisplay(); } }
// AssetPieChartView is an AbstractAccountView subclass that // displays multiple asset Account balances as a pie chart. public class AssetPieChartView extends JPanel implements Observer{ // observes all accounts private List accounts = new ArrayList(); // List of observed accts // add Account to pie chart view public void addAccount( Account anAccount ) { if ( anAccount == null ) // do not add null Accounts throw new NullPointerException(); // add new account to the list of accounts accounts.add( account ); // register as Observer to receive Account updates anAccount.addObserver( this ); // update display with new Account information repaint(); }
// remove Account from pie chart view public void removeAccount( Account anAccount ) { anAccount.deleteObserver( this );// stop receiving updates accounts.remove(anAccount );// remove Account from accounts list colors.remove(anAccount ); // remove Account's Color repaint(); // update display to remove Account information } // receive updates from Observable Account public void update( Observable observable, Object object ) { repaint(); }
// AccountController is a controller for Accounts. It provides // a JTextField for inputting a deposit or withdrawal amount // and JButtons for depositing or withdrawing funds. public class AccountController extends JPanel { private Account account; // Account to control } // AccountManager is an application that uses the MVC design // pattern to manage bank Account information. public class AccountManager extends JFrame { public AccountManager() { super( "Account Manager" ); // create account1 with initial balance Account account1 = new Account( "Account 1", 1000.00 );
/* continuation of constructor for AccountManager */ // create GUIs for account1 JPanel account1Panel = createAccountPanel( account1 ); // create account2 with initial balance Account account2 = new Account( "Account 2", 3000.00 ); // create GUI for account2 JPanel account2Panel = createAccountPanel( account2 ); // create AccountPieChartView to show Account pie chart AssetPieChartView pieChartView = new AssetPieChartView(); // add both Accounts to AccountPieChartView pieChartView.addAccount( account1 ); pieChartView.addAccount( account2 ); } // end AccountManager constructor