CS 635: Advanced Object-Oriented Design & Programming |
---|
Reference | slide # 1 |
Factory Method | slide # 2 |
......Maze Class Version 1 | slide # 3 |
...Implementation | slide # 7 |
......Parameterized Factory Methods | slide # 8 |
......C++ Templates to Avoid Subclassing | slide # 8 |
......Java forName and Factory methods | slide # 9 |
......Clients Can Use Factory Methods | slide # 10 |
Prototype | slide # 12 |
...Intent | slide # 12 |
...Applicability | slide # 12 |
...Implementation/Sample Code | slide # 13 |
...Cloning Issues | slide # 14 |
......How to in C++ - Copy Constructors | slide # 14 |
......How to in Java - Object clone() | slide # 15 |
......Shallow Copy Verse Deep Copy | slide # 16 |
...Example of Prototype | slide # 18 |
...Consequences | slide # 27 |
...Implementation Issues | slide # 27 |
Abstract Factory | slide # 28 |
...How Do Factories create Widgets | slide # 32 |
......Method 2) Their Factory Method | slide # 33 |
......Method 3) Prototype | slide # 35 |
...Applicability | slide # 36 |
...Consequences | slide # 36 |
Now a maze game has to make a maze, so we might have something like:
class MazeGame { public Maze createMaze() { Maze aMaze = new Maze(); Room r1 = new Room( 1 ); Room r2 = new Room( 2 ); Door theDoor = new Door( r1, r2); aMaze.addRoom( r1 ); aMaze.addRoom( r2 ); r1.setSide( North, new Wall() ); r1.setSide( East, theDoor ); r1.setSide( South, new Wall() ); r1.setSide( West, new Wall() ); r2.setSide( North, new Wall() ); r2.setSide( East, new Wall() ); r2.setSide( South, new Wall() ); r2.setSide( West, theDoor ); return aMaze; } }
class BombedMazeGame extends MazeGame { public Maze createMaze() { Maze aMaze = new Maze(); Room r1 = new RoomWithABomb( 1 ); Room r2 = new RoomWithABomb( 2 ); Door theDoor = new Door( r1, r2); aMaze.addRoom( r1 ); aMaze.addRoom( r2 ); r1.setSide( North, new BombedWall() ); r1.setSide( East, theDoor ); r1.setSide( South, new BombedWall() ); r1.setSide( West, new BombedWall() );
Note the amount of cut and paste!
class MazeGame { public Maze makeMaze() { return new Maze(); } public Room makeRoom(int n ) { return new Room( n ); } public Wall makeWall() { return new Wall(); } public Door makeDoor() { return new Door(); } public Maze CreateMaze() { Maze aMaze = makeMaze(); Room r1 = makeRoom( 1 ); Room r2 = makeRoom( 2 ); Door theDoor = makeDoor( r1, r2); aMaze.addRoom( r1 ); aMaze.addRoom( r2 ); r1.setSide( North, makeWall() ); r1.setSide( East, theDoor ); r1.setSide( South, makeWall() ); r1.setSide( West, makeWall() ); r2.setSide( North, makeWall() ); r2.setSide( East, makeWall() ); r2.setSide( South, makeWall() ); r2.setSide( West, theDoor ); return aMaze; } }
CreateMaze method stays the same
class BombedMazeGame extends MazeGame { public Room makeRoom(int n ) { return new RoomWithABomb( n ); } public Wall makeWall() { return new BombedWall(); }
abstract class MazeGame { public Maze makeMaze(); public Room makeRoom(int n ); public Wall makeWall(); public Door makeDoor();
class MazeGame { public: virtual Maze* makeMaze() = 0; virtual Room* makeRoom(int n ) = 0; virtual Wall* makeWall() = 0; virtual Door* makeDoor() = 0;
"Create objects in a separate operation so that subclasses can override the way they're created"
class Hershey { public Candy makeChocolateStuff( CandyType id ) { if ( id == MarsBars ) return new MarsBars(); if ( id == M&Ms ) return new M&Ms(); if ( id == SpecialRich ) return new SpecialRich(); return new PureChocolate(); }
template <class ChocolateType> class Hershey { public: virtual Candy* makeChocolateStuff( ); } template <class ChocolateType> Candy* Hershey<ChocolateType>::makeChocolateStuff( ) { return new ChocolateType; }
Hershey<SpecialRich> theBest;
class Hershey { private String chocolateType; public Hershey( String chocolate ) { chocolateType = chocolate; } public Candy makeChocolateStuff( ) { Class candyClass = Class.forName( chocolateType ); return (Candy) candyClass.newInstance(); }
Hershey theBest = new Heshsey( "SpecialRich" );
class CandyStore { Hershey supplier; public restock() { blah if ( chocolateStock.amount() < 10 ) { chocolateStock.add( supplier.makeChocolateStuff() ); } blah
class Room extends MapSite { public Room makeRoom() { return new Room(); } etc, } class RoomWithBomb extends Room { public Room makeRoom() { return new RoomWithBomb(); } etc, } etc. class MazeGame { public Room roomMaker; etc. public MazeGame( Room rfactory ) { roomMaker = rfactory; } public Maze CreateMaze() { Maze aMaze = new Maze(); Room r1 = roomMaker.makeRoom( 1 ); etc.
class Prototype { public Prototype clone() { code to make a copy of current Prototype object return clone; } // add what ever else you want the class to do } class Protoplasm extends Prototype { public Prototype clone() { code to make a copy of current Protoplasm object return clone; } // add more other stuff } ClientCodeMethod( Prototype example ) { Prototype myCopy = example.clone(); // do some work using myCopy }
class Door { public: Door(); Door( const Door&); virtual Door* clone() const; virtual void Initialize( Room*, Room* ); // stuff not shown private: Room* room1; Room* room2; } Door::Door ( const Door& other ) //Copy constructor { room1 = other.room1; room2 = other.room2; } Door* Door::clone() const { return new Door( *this ); }
Creates a clone of the object. A new instance is allocated and a bitwise clone of the current object is place in the new object.
Returns:
class Door implements Cloneable { public void Initialize( Room a, Room b) { room1 = a; room2 = b; } public Object clone() throws CloneNotSupportedException { return super.clone(); } Room room1; Room room2; }
JavaServer handles the network connection.
Algorithm:
class JavaServer { ServerSocket acceptor; public JavaServer( int portNumber ) { acceptor = new ServerSocket( portNumber ); } public void run() { while (true) { Socket client = acceptor.accept(); InputStream cin = client.getInputStream(); OutputStream cout = client.getOutputStream(); processClientRequest( cin, cout ); } } private void processClientRequest( InputStream cin, OutputStream cout ) { DateServer handler = new DateServer( cin, cout); handler.processClientRequest(); } }
class AirlineReservationJavaServer extends JavaServer { public AirlineReservationServer( int portNumber ) { super( portNumber ); } private void processClientRequest( InputStream cin, OutputStream cout ) AirlineReservation handler; handler = new AirlineReservation( cin, cout ); handler.processClientRequest(); } }
Declare variables to be instances of the abstract class not instances of particular classes
interface ServerEngine { public void processClientRequest(InputStream in, OutputStream out); }
abstract class JavaServer { ServerSocket acceptor; public JavaServer( int portNumber ) { acceptor = new ServerSocket( portNumber ); } public void run() { while (true) { Socket client = acceptor.accept(); InputStream cin = client.getInputStream(); OutputStream cout = client.getOutputStream(); ServerEngine requestHandler = makeServerEngine(); requestHandler.processClientRequest( cin, cout ); } } abstract protected ServerEngine makeServerEngine(); }
class AirlineReservationJavaServer extends JavaServer { public AirlineReservationServer( int portNumber ) { super( portNumber ); } protected ServerEngine makeServerEngine() { return new AirlineReservation( ); } } class AirlineReservation implements ServerEngine { public void processClientRequest(InputStream in, OutputStream out) { blah } etc. }
interface ServerEngine { public ServerEngine clone( InputStream in, OutputStream out ); public void processClientRequest(); }
class JavaServer { ServerSocket acceptor; ServerEngine serverPrototype; public JavaServer( int portNumber, ServerEngine aCopy) { acceptor = new ServerSocket( portNumber ); serverPrototype = aCopy; } public void run() { while (true) { Socket client = acceptor.accept(); InputStream cin = client.getInputStream(); OutputStream cout = client.getOutputStream(); ServerEngine requestHandler = serverPrototype.clone( cin, cout); requestHandler.processClientRequest( cin, cout ); } } }Driver Program
class DriverProgram { public static void main( String args[] ) { ServerEngine aPrototype = new DateServer(); JavaServer networkListener; networkListener = new JavaServer( 6666, aPrototype ); networkListener.run(); } }
We will look at widgets: Windows, Menu's and Buttons
Create an interface( or abstract class) for each widget and an concrete class for each platform:
public void installDisneyMenu() { Menu disney = create a menu somehow disney.addItem( "Disney World" ); disney.addItem( "Donald Duck" ); disney.addItem( "Mickey Mouse" ); disney.addGrayBar( ); disney.addItem( "Minnie Mouse" ); disney.addItem( "Pluto" ); etc. }
How to create the widget?
abstract class WidgetFactory { public Window createWindow(); public Menu createMenu(); public Button createButton(); } class MacWidgetFactory extends WidgetFactory { public Window createWindow() { code to create a mac window } public Menu createMenu() { code to create a mac Menu } public Button createButton() { code to create a mac button } } class Win95WidgetFactory extends WidgetFactory { public Window createWindow() { code to create a Win95 window } public Menu createMenu() { code to create a Win95 Menu } public Button createButton() { code to create a Win95 button } }Etc.
public void installDisneyMenu(WidgetFactory myFactory) { Menu disney = myFactory.createMenu(); disney.addItem( "Disney World" ); disney.addItem( "Donald Duck" ); disney.addItem( "Mickey Mouse" ); disney.addGrayBar( ); disney.addItem( "Minnie Mouse" ); disney.addItem( "Pluto" ); etc. }
abstract class WidgetFactory { public Window createWindow(); public Menu createMenu(); public Button createButton(); } class MacWidgetFactory extends WidgetFactory { public Window createWindow() { return new MacWidow() } public Menu createMenu() { return new MacMenu() } public Button createButton() { return new MacButton() } }
abstract class WidgetFactory { private Window windowFactory; private Menu menuFactory; private Button buttonFactory; public Window createWindow() { return windowFactory.createWindow() } public Menu createMenu(); { return menuFactory.createWindow() } public Button createButton() { return buttonFactory.createWindow() } } class MacWidgetFactory extends WidgetFactory { public MacWidgetFactory() { windowFactory = new MacWindow(); menuFactory = new MacMenu(); buttonFactory = new MacButton(); } }
class MacWindow extends Window { public Window createWindow() { blah } etc.
abstract class WidgetFactory { private Window windowFactory; private Menu menuFactory; private Button buttonFactory; public Window createWindow() { return windowFactory.createWindow() } public Window createWindow( Rectangle size) { return windowFactory.createWindow( size ) } public Window createWindow( Rectangle size, String title) { return windowFactory.createWindow( size, title) } public Window createFancyWindow() { return windowFactory.createFancyWindow() } public Window createPlainWindow() { return windowFactory.createPlainWindow() }Using factory method allows abstract class to do all the different ways to create a window.
Subclasses just provide the objects windowFactory,
menuFactory, buttonFactory, etc.
class WidgetFactory { private Window windowPrototype; private Menu menuPrototype; private Button buttonPrototype; public WidgetFactory( Window windowPrototype, Menu menuPrototype, Button buttonPrototype) { this.windowPrototype = windowPrototype; this.menuPrototype = menuPrototype; this.buttonPrototype = buttonPrototype; } public Window createWindow() { return windowFactory.createWindow() } public Window createWindow( Rectangle size) { return windowFactory.createWindow( size ) } public Window createWindow( Rectangle size, String title) { return windowFactory.createWindow( size, title) } public Window createFancyWindow() { return windowFactory.createFancyWindow() }
There is no need for subclasses of WidgetFactory.
public void installDisneyMenu(WidgetFactory myFactory) { // We ship next week, I can't get the stupid generic Menu to // do the fancy Mac menu stuff // Windows version won't ship for 6 months // Will fix this later MacMenu disney = (MacMenu) myFactory.createMenu(); disney.addItem( "Disney World" ); disney.addItem( "Donald Duck" ); disney.addItem( "Mickey Mouse" ); disney.addMacGrayBar( ); disney.addItem( "Minnie Mouse" ); disney.addItem( "Pluto" ); etc. }