View
220
Download
0
Embed Size (px)
Citation preview
Topics Covered
• Multiple inheritance– Extending more than one type
• Factories– Class creating objects
• Facades– Compose objects
• Can be used independently– We use them together here
• Factory methods– Abstract method instead of class
Problem
• A modification to the course problem.
• Want to gather statistics on how many times a user requested a course– How many times matchTitle() successfully
matched a course
Old Course Interface
package courseTree;public interface Course extends TreeNode {
public String getTitle();public String getDepartment();public int getNumber();public void init (String theTitle, String theDept);
}
New Course Interface
package courseTree;public interface LoggedCourse extends Course {
public int getNumberOfQueries();
}
Old abstract classpackage courseTree;public abstract class ACourse implements Course {
String title, dept;public ACourse (String theTitle, String theDept) {
init (theTitle, theDept);}public ACourse () {}public void init (String theTitle, String theDept) {
title = theTitle;dept = theDept;
}public String getTitle() {return title;}public String getDepartment() {return dept; }public Course matchTitle(String theTitle) {
if ( title.equals(theTitle)) return this;else return null;
}}
New abstract classpackage courseTree;public abstract class ALoggedCourse extends ACourse implements LoggedCourse {
int numberOfQueries = 0;public ALoggedCourse (String theTitle, String theDept) {
super (theTitle, theDept);}public ALoggedCourse () {}public int getNumberOfQueries() {
return numberOfQueries;}public Course matchTitle(String theTitle) {
Course course = super.matchTitle(theTitle);if (course != null) numberOfQueries++;return course;
}}
Old Regular Course Interfacepackage courseTree;public interface RegularCourse extends Course {
public void init (String theTitle, String theDept, int theCourseNum);}
New Regular Course Interfacepackage courseTree;public interface LoggedRegularCourse extends LoggedCourse {
public void init (String theTitle, String theDept, int theCourseNum);}
Duplication
package courseTree;public interface LoggedRegularCourse extends LoggedCourse {
public void init (String theTitle, String theDept, int theCourseNum);}
package courseTree;public interface RegularCourse extends Course {
public void init (String theTitle, String theDept, int theCourseNum);}
LoggedRegularCourse IS-A RegularCourse
Single Interface Inheritance
package courseTree;public interface LoggedRegularCourse extends LoggedCourse { public void init (String theTitle, String theDept, int theCourseNum);}
public interface RegularCourse extends Course { public void init (String theTitle, String theDept, int theCourseNum);}
public interface Course extends TreeNode { public String getTitle(); public String getDepartment(); public int getNumber(); public void init (String theTitle, String theDept);}
public interface LoggedCourse extends Course { public int getNumberOfQueries();}
Course
LoggedCourse RegularCourse
LoggedRegularCourse
Alternative Single Inheritance
package courseTree;public interface LoggedRegularCourse extends RegularCourse { public int getNumberOfQueries();}
public interface RegularCourse extends Course { public void init (String theTitle, String theDept, int theCourseNum);}
public interface Course extends TreeNode { public String getTitle(); public String getDepartment(); public int getNumber(); public void init (String theTitle, String theDept);}
public interface LoggedCourse extends Course { public int getNumberOfQueries();}
Course
LoggedCourse RegularCourse
LoggedRegularCourse
Multiple Interface Inheritance
package courseTree;public interface LoggedRegularCourse extends LoggedCourse, RegularCourse{}
package courseTree;public interface RegularCourse extends Course {
public void init (String theTitle, String theDept, int theCourseNum);}
package courseTree;public interface LoggedCourse extends Course {
public int getNumberOfQueries();}
empty interface
Multiple Interface Inheritance
public interface LoggedRegularCourse extends RegularCourse {}
public interface RegularCourse extends Course { public void init (String theTitle, String theDept, int theCourseNum);}
public interface Course extends TreeNode { public String getTitle(); public String getDepartment(); public int getNumber(); public void init (String theTitle, String theDept);}
public interface LoggedCourse extends Course { public int getNumberOfQueries();}
Course
LoggedCourse RegularCourse
LoggedRegularCourse
empty interface
Old Regular Course Classpublic class ARegularCourse extends ACourse implements RegularCourse {
int courseNum ;public ARegularCourse (String theTitle, String theDept, int
theCourseNum) {init (theTitle, theDept, theCourseNum);
} public ARegularCourse () {} public void init (String theTitle, String theDept, int theCourseNum) {
super.init (theTitle, theDept);courseNum = theCourseNum;
} public int getNumber() {
return courseNum;}
}
New Regular Course Classpublic class ALoggedRegularCourse extends ALoggedCourse implements LoggedRegularCourse {
int courseNum ;public ALoggedRegularCourse (String theTitle, String theDept, int
theCourseNum) {init (theTitle, theDept, theCourseNum);
} public ALoggedRegularCourse () {} public void init (String theTitle, String theDept, int theCourseNum) {
super.init (theTitle, theDept);courseNum = theCourseNum;
} public int getNumber() {
return courseNum;}
}
Code duplication and ALoggedRegularCourse is not ARegularCourse!
Single Class Inheritance
public interface LoggedRegularCourse extends ALoggedCourse { public int getNumber() {…}; public void init (String theTitle, String theDept, int theCourseNum) {…};}
public class ARegularCourse extends ACourse { public int getNumber() {…}; public void init (String theTitle, String theDept, int theCourseNum);}
public class ACourse implements Course { public String getTitle() {…} public String getDepartment() {…}; public void init (String theTitle, String theDept) {…}; public Course matchTitle (String theTitle) {…};}
public class ALoggedCourse extends ACourse { public int getNumberOfQueries() {…}; public Course matchTitle (String theTitle) {…}; }
ACourse
ALoggedCourse ARegularCourse
ALoggedRegularCourse
Multiple Class Inheritance?
public class LoggedRegularCourse extends ALoggedCourse, ARegularCourse {}
public class ARegularCourse extends ACourse { public int getNumber() {…}; public void init (String theTitle, String theDept, int theCourseNum);}
public class ACourse implements Course { public String getTitle() {…} public String getDepartment() {…}; public void init (String theTitle, String theDept) {…}; public Course matchTitle (String theTitle) {…};}
public class ALoggedCourse extends ACourse { public int getNumberOfQueries() {…}; public Course matchTitle (String theTitle) {…}; }
ACourse
ALoggedCourse ARegularCourse
ALoggedRegularCourse
Multiple Class Inheritance?public class ALoggedRegularCourse extends ALoggedCourse, ARegularCourse implements LoggedRegularCourse {}
public abstract class ALoggedCourse extends ACourse implements LoggedCourse {…public Course matchTitle(String theTitle) {
Course course = super.matchTitle(theTitle);if (course != null) numberOfQueries++;return course;
}}
public class ARegularCourse extends ACourse implements RegularCourse {…}
public abstract class ACourse implements Course {…public Course matchTitle(String theTitle) {
if ( title.equals(theTitle)) return this;else return null;
}}
Two different implementations with same header inherited
Multiple inheritance rules• Allow interfaces to inherit multiple times
– Only headers are inherited
• Do not allow classes to inherit multiple times (Java)– Could inherit multiple bodies with same header– Can be confusing to programmers
• Other solutions– Allow multiple inheritance if ambiguity does not arise– If ambiguity arises indicate which implementation is
used (C++)• ALoggedCourse.matchTitle() vs ARegularCourse.matchTitle()
– Choose one or none of the bodies if problem arises• Based on order in extends clause?• extends ALoggedCourse, ARegularCourse
Multiple Interface Inheritance
public interface LoggedRegularCourse extends RegularCourse, LoggedCourse{}
public interface RegularCourse extends Course { public void init (String theTitle, String theDept, int theCourseNum);}
public interface Course extends TreeNode { public String getTitle(); public String getDepartment(); public int getNumber(); public void init (String theTitle, String theDept);}
public interface LoggedCourse extends Course { public int getNumberOfQueries();}
Course
LoggedCourse RegularCourse
LoggedRegularCourse
Same method headers added twice, no problem
Multiple Interface Inheritance
public interface LoggedRegularCourse extends RegularCourse, LoggedCourse {}
public interface RegularCourse extends Course { public void init (String theTitle, String theDept, int theCourseNum);}
public interface Course extends TreeNode { public String getTitle(); public String getDepartment(); public int getNumber(); public void init (String theTitle, String theDept);}
public interface LoggedCourse extends Course { public int getNumberOfQueries(); public void init (String theTitle, String theDept);}
Course
LoggedCourse RegularCourse
LoggedRegularCourse
Equal method headers inherited twice
Interface: set of method headersAddition: removes duplicates
Multiple Interface Inheritance
public interface LoggedRegularCourse extends RegularCourse, LoggedCourse {}
public interface RegularCourse extends Course { public void init (String theTitle, String theDept, int theCourseNum);}
public interface Course extends TreeNode { public String getTitle(); public String getDepartment(); public int getNumber(); public void init (String theTitle, String theDept);}
public interface LoggedCourse extends Course { public int getNumberOfQueries(); public LoggedCourse init (String theTitle, String theDept);
}
Course
LoggedCourse RegularCourse
LoggedRegularCourse
Method headers differ only in return type
Overloading ambiguity, multiple inheritance not allowed
Single inheritance => reduced polymorphsism?
public class ALoggedRegularCourse extends ALoggedCourse implements LoggedRegularCourse { … }
void print (ARegularCourse course) {…}
ALoggedRegularCourse introProg = new ALoggedRegularRegularCourse();….print(introProg);
LoggedRegularCourse introProg = new ALoggedRegularRegularCourse();….print(introProg);
void print (RegularCourse course) {…}
Code Duplication & ALoggedRegularCourse is not ARegularCourse!
Classes as types
Interfaces as types
Single inheritance => reduced polymorphism?
• Yes, if classes used to type variables
• Interfaces offer solution to lack of multiple (class) inheritance in Java
• Most programmers do not realise other uses.
• In text books, interfaces introduced and used only in problems requiring multiple inheritance
Implementing Single Interfacepublic class ALoggedRegularCourse extends ALoggedCourse implements LoggedRegularCourse {
int courseNum ;public ALoggedRegularCourse (String theTitle, String theDept, int
theCourseNum) {init (theTitle, theDept, theCourseNum);
} public ALoggedRegularCourse () {} public void init (String theTitle, String theDept, int theCourseNum) {
super.init (theTitle, theDept);courseNum = theCourseNum;
} public int getNumber() {
return courseNum;}
}
package courseTree;public interface LoggedRegularCourse extends LoggedCourse, RegularCourse{}
Implementing Multiple Interfacespublic class ALoggedRegularCourse extends ALoggedCourse implements LoggedCourse, RegularCourse {
int courseNum ;public ALoggedRegularCourse (String theTitle, String theDept, int
theCourseNum) {init (theTitle, theDept, theCourseNum);
} public ALoggedRegularCourse () {} public void init (String theTitle, String theDept, int theCourseNum) {
super.init (theTitle, theDept);courseNum = theCourseNum;
} public int getNumber() {
return courseNum;}
}
Multiple interfaces => Casting
LoggedCourse introProg = new ALoggedRegularRegularCourse();….print((RegularCourse)introProg);….appendToLog(introProg);
public class ALoggedRegularCourse extends ALoggedCourse implements LoggedCourse, RegularCourse { …. }
RegularCourse introProg = new ALoggedRegularRegularCourse();….print(introProg);….appendToLog((LoggedCourse)introProg);
void print (RegularCourse course) {…}
void appendToLog (LoggedCourse course) {…}
Single interface
LoggedregularCourse introProg = new ALoggedRegularRegularCourse();….print (introProg);….appendToLog(introProg);
void print (RegularCourse course) {…}
void appendToLog (LoggedCourse course) {…}
public class ALoggedRegularCourse extends ALoggedCourse implements LoggedRegularCourse { …. }
Single interface and overloading
LoggedRegularCourse introProg = new ALoggedRegularRegularCourse();….print ((RegularCourse)introProg);….appendToLog((LoggedCourse)introProg);
void print (RegularCourse course) {…}
void print (LoggedCourse course) {…}
public class ALoggedRegularCourse extends ALoggedCourse implements LoggedRegularCourse { …. }
Implementing multiple interfaces vs. Single Interface
• Different interfaces evolved independently– TreeNode, LeafOnly,
CompositeOnly
– LoggedCourse, RegularCourse
• Uniting them creates empty interface
• Does not require casting to use different interfaces of same object
• Modulo overloading problems– These arise whenever an
object can be typed in multiple ways.
– A compile time issue – these casts are needed only at compile time and do not lead to runtime errors.
Switching between different course configurations
• Want both logged and non-logged versions based on users– Logged course has overhead– Some university may decide logging gives
misleading /useless information
• How to write programs that can easily switch between the two kinds of courses
ACourseListpackage courseTree;public class ACourseList implements CourseList, TreeNode {
final int MAX_SIZE = 50;TreeNode[] contents = new TreeNode[MAX_SIZE];int size = 0;public int size() {return size;}public TreeNode elementAt (int index) {return contents[index];}boolean isFull() { return size == MAX_SIZE;}public void addElement(TreeNode element) { if (isFull()) System.out.println("Adding item to a full collection"); else { contents[size] = element;
size++; }}public Course matchTitle (String theTitle) {
for (int courseIndex = 0; courseIndex < size; courseIndex++) { Course course = contents[courseIndex].matchTitle(theTitle); if ( course != null) return course;
} return null;
}}
Using interfaces as typesOblivious to actual classes
Main Classpackage main;…public class ACourseDisplayer {
static CourseList courses = new ACourseList();public static void main(String[] args) {
fillCourses();//Do I/O…
}...static void fillCourses() {
CourseList prog = new ACourseList();prog.addElement (new ARegularCourse ("Intro. Prog.", "COMP", 14));prog.addElement (new ARegularCourse ("Found. of Prog.", "COMP", 114));
courses.addElement(prog);courses.addElement (new AFreshmanSeminar("Comp. Animation",
"COMP"));courses.addElement (new AFreshmanSeminar("Lego Robots", "COMP"));
}}
Switching between classes
• How to make main and other classes instantiating course objects oblivious to which course set is used?
• How to make sure incompatible courses are not added to course list– AFreshmanSeminar– ALoggedRegularCourse
Factory class
• Creates a set of related objects• Different factory classes for different
configurations– ACourseFactory
– ALoggedCourseFactory
• Factory classes providing alternative configurations implement the same interface– CourseFactory
Common Factory Interface
package factories;import courseTree.RegularCourse;import courseTree.FreshmanSeminar;public interface CourseFactory {
public RegularCourse getRegularCourse();public FreshmanSeminar getFreshmanSeminar();
}
ACourseFactory
package factories;import courseTree.RegularCourse;import courseTree.FreshmanSeminar;import courseTree.ARegularCourse;import courseTree.AFreshmanSeminar;public class ACourseFactory implements CourseFactory {
public RegularCourse getRegularCourse() {return new ARegularCourse();
}public FreshmanSeminar getFreshmanSeminar() {
return new AFreshmanSeminar();}
}
Parameterless constructorsFactory user will call init()
ALoggedCourseFactory
package factories;import courseTree.RegularCourse;import courseTree.FreshmanSeminar;import courseTree.ALoggedRegularCourse;import courseTree.ALoggedFreshmanSeminar;public class ALoggedCourseFactory implements CourseFactory{
public RegularCourse getRegularCourse() {return new ALoggedRegularCourse();
}public FreshmanSeminar getFreshmanSeminar() {
return new ALoggedFreshmanSeminar();}
}
Original Main Classpackage main;…public class ACourseDisplayer {
static CourseList courses = new ACourseList();public static void main(String[] args) {
fillCourses();//Do I/O…
}...static void fillCourses() {
CourseList prog = new ACourseList();prog.addElement (new ARegularCourse ("Intro. Prog.", "COMP", 14));prog.addElement (new ARegularCourse ("Found. of Prog.", "COMP", 114));…
}}
New Main Classpackage main;…public class AFactoryBasedCourseDisplayer {
static CourseList courses = new ACourseList();public static void main(String[] args) {
fillCourses();//Do I/O…
}...static void fillCourses() {
CourseFactory courseFactory = new ACourseFactory();CourseList prog = new ACourseList();RegularCourse introProg = courseFactory.getRegularCourse ();introProg.init("Intro. Prog.", "COMP", 14);RegularCourse foundProg = courseFactory.getRegularCourse ();foundProg.init(“Found. Prog.", "COMP", 114);…
}}
New Main Class for logged coursespackage main;…public class AFactoryBasedCourseDisplayer {
static CourseList courses = new ACourseList();public static void main(String[] args) {
fillCourses();//Do I/O…
}...static void fillCourses() {
CourseFactory courseFactory = new ALoggedCourseFactory();CourseList prog = new ACourseList();RegularCourse introProg = courseFactory.getRegularCourse ();introProg.init("Intro. Prog.", "COMP", 14);RegularCourse foundProg = courseFactory.getRegularCourse ();foundProg.init(“Found. Prog.", "COMP", 114);
…}
}
Factory Transparent Main?
• Same main and other course users for different configurations?
• Need FactorySelector Class– Only class changed to select different
configurations
• Main and other classes call factory selector class
Factory Selector Interface
package factories;public interface CourseFactorySelector {
public CourseFactory getCourseFactory();}
Factory Selector Class
package factories;public class ACourseFactorySelector implements CourseFactorySelector {
public CourseFactory getCourseFactory() {//return new ACourseFactory();return new ALoggedCourseFactory();
}}
Main Class with Factory Selectorpackage main;…public class AFactoryBasedCourseDisplayer {
static CourseList courses = new ACourseList();public static void main(String[] args) {
fillCourses();//Do I/O…
}...static void fillCourses() { CourseFactory courseFactory = (new CourseFactorySelector()).getCourseFactory(); CourseList prog = new ACourseList(); RegularCourse introProg = courseFactory.getRegularCourse (); introProg.init("Intro. Prog.", "COMP", 14); RegularCourse foundProg = courseFactory.getRegularCourse (); foundProg.init(“Found. Prog.", "COMP", 114);
…}
}
Different Selection
package factories;public class ACourseFactorySelector {
public CourseFactory getCourseFactory() {return new ACourseFactory();//return new ALoggedCourseFactory();
}}
No change to main and other users needed!
ALoggedCourseFactory
package factories;import courseTree.RegularCourse;import courseTree.FreshmanSeminar;import courseTree.ALoggedRegularCourse;import courseTree.ALoggedFreshmanSeminar;public class ALoggedCourseFactory implements CourseFactory{
public RegularCourse getRegularCourse() {return new ALoggedRegularCourse();
}public FreshmanSeminar getFreshmanSeminar() {
return new ALoggedFreshmanSeminar();}
}
Classes that need logged courses must cast
Logged Factory Interface
package factories;import courseTree.LoggedRegularCourse;import courseTree.LoggedFreshmanSeminar;public interface LoggedCourseFactory extends CourseFactory {
public LoggedRegularCourse getLoggedRegularCourse();public LoggedFreshmanSeminar getLoggedFreshmanSeminar();
}
ALoggedCourseFactorypackage factories;import courseTree.RegularCourse;import courseTree.FreshmanSeminar;import courseTree.LoggedRegularCourse;import courseTree.LoggedFreshmanSeminar;import courseTree.ALoggedRegularCourse;import courseTree.ALoggedFreshmanSeminar;public class ALoggedCourseFactory implements LoggedCourseFactory {
public RegularCourse getRegularCourse() {return new ALoggedRegularCourse();
}public FreshmanSeminar getFreshmanSeminar() {
return new ALoggedFreshmanSeminar();}public LoggedRegularCourse getLoggedRegularCourse() {
return new ALoggedRegularCourse();}public LoggedFreshmanSeminar getLoggedFreshmanSeminar() {
return new ALoggedFreshmanSeminar();}
}
Classes vs. Factory• We also called a class a factory
– It defines blueprints for its instances
• Factory in factory pattern is really a broker that orders objects for you
• Factory selector decides between different kinds of brokers
• Analogy– I ask my IT department to get me a 4lb laptop– They decide to go to the IBM CCI “factory” – CCI factory specifies matching computer and
accessories– These are then ordered from the real IBM factory
Factory Uses
• Should we always instantiate via factories?• Factories add overhead
– Factory interfaces, classes
– Factory selector interfaces, classes
• Define when you need them– Need to switch transparently between alternates
• BMISpreadsheet and AnotherBMISpreadsheet
– Need to ensure matching objects are created• ALoggedFreshmanSeminar and ALoggedRegularCourse
Programmer Selection• Multiple toolkits provided to programmer.• Package java.awt
– TextField, Button, Panel
• Package javax.swing– JTextField, JButton, JPanel
• Could define a common factory interface– getTextField(), getButton(), getPanel()
• SwingFactory and AWTFactory classes implement interface
• Programmer-defined FactorySelector switches between two classes to change implementation
Factory uses• Multiple toolkits provide same kind of widgets with
different look and feel/implementations.• Package java.awt
– TextField, Button, Panel
• Package javax.swing– JTextField, JButton, JPanel
• Could define a common factory interface– getTextField(), getButton(), getPanel()
• SwingFactory and AWTFactory classes implement interface
• FactorySelector switches between two classes to change implementation
Factory Uses• Multiple implementation of AWT toolkit for
each window system.– Microsoft Windows.– X Windows
Factories and Interfaces• Factories allow us to switch between alternative objects
providing same methods– FreshmanSeminar and LoggedFreshmanSeminar– JTextField and TextField
• Alternative objects must be united by a common interface• Otherwise common factory interface cannot be defined.• Desired toolkit factory interface
– getTextField(), getButton(), getPanel()• JTextField and TextField do not define a common text field
interface• Though they provide common methods
– getText(), setText()• Moral: define interfaces!
Reducing Main Class through Facades
• Things to exclude– “computation”
• Things to include– Input/Output– Object instantiation
• Unless done byfactory
– Object composition
• Main class still monolithic• Facades
– Do object composition
Main class without Façadepackage main;…public class AFactoryBasedCourseDisplayer {
static CourseList courses = new ACourseList();public static void main(String[] args) {
fillCourses();while (true) {
System.out.println("Please enter course title:");String inputLine = readString();if (inputLine.equals("."))
break;else {
Course matchedCourse = courses.matchTitle(inputLine);if (matchedCourse == null)
System.out.println("Sorry, this course is not offered.");
else {printHeader();print (matchedCourse);
} }}
Main Class without Façade
...
static void fillCourses() { CourseFactory courseFactory = (new CourseFactorySelector()).getCourseFactory(); CourseList prog = new ACourseList(); RegularCourse introProg = courseFactory.getRegularCourse (); introProg.init("Intro. Prog.", "COMP", 14); RegularCourse foundProg = courseFactory.getRegularCourse (); foundProg.init(“Found. Prog.", "COMP", 114);
…}…
}
Composes courses and course lists
Main class with Façade (edit)package main;…public class AFactoryBasedCourseDisplayer {
static CourseList courses = new ACourseList();public static void main(String[] args) {
fillCourses();while (true) {
System.out.println("Please enter course title:");String inputLine = readString();if (inputLine.equals("."))
break;else {
Course matchedCourse = courses.matchTitle(inputLine);if (matchedCourse == null)
System.out.println("Sorry, this course is not offered.");
else {printHeader();print (matchedCourse);
} }}
Main class with Façade (edited)package main;…public class AFactoryBasedCourseDisplayer {
static Facade courses = new AFacade();public static void main(String[] args) {
//fillCourses();while (true) {
System.out.println("Please enter course title:");String inputLine = readString();if (inputLine.equals("."))
break;else {
Course matchedCourse = courses.matchTitle(inputLine);if (matchedCourse == null)
System.out.println("Sorry, this course is not offered.");
else {printHeader();print (matchedCourse);
} }}
Main class with façadepackage main;…public class AFactoryBasedCourseDisplayer {
static TitleToCourseMapper titleToCourseMapper = new ATitleToCourseMapper();public static void main(String[] args) {
while (true) {System.out.println("Please enter course title:");String inputLine = readString();if (inputLine.equals("."))
break;else {
titleToCourseMapper.setTitle(inputLine);Course matchedCourse =
titleToCourseMapper.getCourse();if (matchedCourse == null)
System.out.println("Sorry, this course is not offered.");
else {printHeader();print (matchedCourse);
} }}
Façade interface
package facades;import courseTree.Course;public interface TitleToCourseMapper {
public String getTitle();public void setTitle (String newVal);public Course getCourse();
}
Façade Classpackage facades;import courseTree.Course;import courseTree.RegularCourse;import courseTree.FreshmanSeminar;import courseTree.CourseList;import courseTree.ACourseList;import factories.CourseFactory;import factories.ACourseFactorySelector;public class AFactoryBasedTitleToCourseMapper implements TitleToCourseMapper {
CourseList courses = new ACourseList();public AFactoryBasedTitleToCourseMapper() {
fillCourses();}String title = "";public String getTitle() {return title;}public void setTitle (String newVal) {
title = newVal;course = courses.matchTitle(title);
}Course course;public Course getCourse() {
return courses.matchTitle(title);}
Façade Class void fillCourses() {
CourseFactory courseFactory = (new ACourseFactorySelector()).getCourseFactory();
CourseList prog = new ACourseList();RegularCourse introProg = courseFactory.getRegularCourse ();introProg.init("Intro. Prog.", "COMP", 14);prog.addElement(introProg);RegularCourse foundProg = courseFactory.getRegularCourse();foundProg.init ("Found. of Prog.", "COMP", 114);prog.addElement(foundProg);courses.addElement(prog);FreshmanSeminar compAnimation = courseFactory.getFreshmanSeminar();compAnimation.init("Comp. Animation", "COMP");courses.addElement(compAnimation);FreshmanSeminar legoRobots = courseFactory.getFreshmanSeminar();legoRobots.init("Lego Robots", "COMP");courses.addElement(legoRobots);
}
}
Façade class
• Done with getters and setters for generality purposes
• Helps with creating GUI interfaces in future
• Provide getters and setters in your facades
Façade pattern• Compose objects into a single unit exposing methods
relevant to that unit• E.g. scanner, parser, program tree, code generator objects
combined into one compiler object– Takes program text as input– Produces code as output– Passes text to scanner, which passes tokens to parser, which
creates program tree, which is processed by code generator, which produces output
• Compiler user not aware of internal components• Componentizing code is a pain as components must be
combined• Facades removes this problem, creating a simple façade to
complex internals
Factory-based Façade Classpackage facades;…public class AFactoryBasedTitleToCourseMapper implements TitleToCourseMapper {
… void fillCourses() {
CourseFactory courseFactory = (new ACourseFactorySelector()).getCourseFactory();
RegularCourse introProg = courseFactory.getRegularCourse ();FreshmanSeminar legoRobots = courseFactory.getFreshmanSeminar();…
…}
}
Application-specific factory
• Factory switching occurs for all classes
• What if we want it for some subset of classes
Factory Method
• Creates objects
• Could be abstract
• Subclasses override it to create objects of different classes
• Change in subclass does not change other subclasses
Abstract facade classpackage facades;import courseTree.Course;import courseTree.RegularCourse;import courseTree.FreshmanSeminar;import courseTree.CourseList;import courseTree.ACourseList;public abstract class AnAbstractTitleToCourseMapper implements TitleToCourseMapper
{…abstract RegularCourse getRegularCourse();abstract FreshmanSeminar getFreshmanSeminar();void fillCourses() {
RegularCourse introProg = getRegularCourse ();FreshmanSeminar legoRobots = getFreshmanSeminar();…
…}
}
Concrete course userpackage facades;import courseTree.Course;import courseTree.RegularCourse;import courseTree.FreshmanSeminar;import courseTree.ARegularCourse;import courseTree.AFreshmanSeminar;public class ATitleToCourseMapper extends AnAbstractTitleToCourseMapper {
RegularCourse getRegularCourse() {return new ARegularCourse();
}FreshmanSeminar getFreshmanSeminar() {
return new AFreshmanSeminar();}
}
Logged course userpackage facades;import courseTree.Course;import courseTree.RegularCourse;import courseTree.FreshmanSeminar;import courseTree.ALoggedRegularCourse;import courseTree.ALoggedFreshmanSeminar;public class ATitleToLoggedCourseMapper extends AnAbstractTitleToCourseMapper {
RegularCourse getRegularCourse() {return new ALoggedRegularCourse();
}FreshmanSeminar getFreshmanSeminar() {
return new ALoggedFreshmanSeminar();}
}
Factory Methods in Course Example
AnAbstractTitleToCourseMapper { defines createRegularCourse and
createFreshmanSeminar and uses them}
ATitleToCourseMapper { implements these
methods to create one configuration }
ATitleToLoggedCourseMapper { implements these methods to create another configuration }
extends
Factory Method Pattern
Abstract Class { defines and uses class creation methods}
Concrete Class { implements these
methods to create some configuration }
Concrete Class { implements these methods to create some
configuration}
extends
Factory Methods in Course Example
AnAbstractTitleToCourseMapper { defines createRegularCourse and
createFreshmanSeminar and uses them}
ATitleToCourseMapper { implements these
methods to create one configuration }
ATitleToLoggedCourseMapper { implements these methods to create another configuration }
extends
ATitleToLoggedCourseMapper IS-A ATitleToCourseMapper
Factory Methods in Course ExampleAnAbstractTitleToCourseMapper { defines
createRegularCourse and createFreshmanSeminar and uses them}
ATitleToCourseMapper { implements these
methods to create one configuration }
ATitleToLoggedCourseMapper { implements these methods to create another configuration }
extends
ATitleToLoggedCourseMapper IS-A ATitleToCourseMapper
extends
Redundant class with a single user
Alternative Factory Method Usage
ATitleToCourseMapper { implements createRegularCourse and
createFreshmanSeminar and uses them}
ATitleToLoggedCourseMapper { overrides these methods to create an
extension}
extends
Factory methods
• Do not have to be abstract– Though pattern book says they are
• A concrete class may define and use class creation methods
• Some subclass of it overrides them• The subclass must extend the functionality• ATitleToLoggedCourseMapper IS-A
ATitleToCourseMapper as LoggedCourse IS-A Course
Alternative Factory Method Usage
ATitleToCourseMapper { implements createRegularCourse and
createFreshmanSeminar and uses them}
ATilteToLoggedCourseMapper { overrides these methods to create an
extension}
extends
Façade super classpublic class ATitleToCourseMapper implements TitleToCourseMapper {
…RegularCourse getRegularCourse() {
return new ARegularCourse();}FreshmanSeminar getFreshmanSeminar() {
return new AFreshmanSeminar();} void fillCourses() {
RegularCourse introProg = getRegularCourse ();FreshmanSeminar legoRobots = getFreshmanSeminar();… …
}}
Logged course subclasspublic class ATitleToLoggedCourseMapper extends ATitleToCourseMapper {
RegularCourse getRegularCourse() {return new ALoggedRegularCourse();
}FreshmanSeminar getFreshmanSeminar() {
return new ALoggedFreshmanSeminar();}
}
Overridden methods
Generalized Factory Method Pattern
Abstract/Concrete Class { defines and maybe implements object creation methods}
Concrete Class { overrides these implementaions to create
an extension}
extends
Concrete Class { overrides these implementaions to create
an extension}
Factory Classes vs. Factory Methods
• Create a configuration applying to all users of a factory selector
• Creates local configurations.
• If class C implements abstract factory method defined in super class S, then configuration applies to C, and all subclasses of C and superclasses between C and S that do not override/implement it
Factory Classes vs. Methodspublic class AFactoryBasedTitleToCourseMapper implements TitleToCourseMapper {
… void fillCourses() {
CourseFactory courseFactory = (new ACourseFactorySelector()).getCourseFactory();
RegularCourse introProg = courseFactory.getRegularCourse ();FreshmanSeminar legoRobots = courseFactory.getFreshmanSeminar();…
}}
public class ATitleToCourseMapper implements TitleToCourseMapper {…RegularCourse getRegularCourse() {return new ARegularCourse();}FreshmanSeminar getFreshmanSeminar() {return new AFreshmanSeminar();} void fillCourses() {
RegularCourse introProg = getRegularCourse ();FreshmanSeminar legoRobots = getFreshmanSeminar();…
}
Lots of methods possible, which may return incompatible objects
Factory Classes and Methodspublic class AFactoryBasedTitleToCourseMapper implements TitleToCourseMapper {
… void fillCourses() {
CourseFactory courseFactory = (new ACourseFactorySelector()).getCourseFactory();
RegularCourse introProg = courseFactory.getRegularCourse ();FreshmanSeminar legoRobots = courseFactory.getFreshmanSeminar();…
}}
public class ATitleToCourseMapper implements TitleToCourseMapper {…RegularCourse getCoursefactory() {return new ARegularCourseFactory();}void fillCourses() {
CourseFactory courseFactory = getCourseFactory();RegularCourse introProg = courseFactory.getRegularCourse ();FreshmanSeminar legoRobots = courseFactory.getFreshmanSeminar();…
}} Single factory method simply acts as factory selector.
Combining factories and factory methods
Abstract/Concrete Class { defines and maybe implements method to
choose factory}
Concrete Class { implements this methods to create some
configuration }
Concrete Class { implements this method to create some
configuration}
extends
Electronics Example• VCR interface
– setChannel(), getChannel(), power(),record(), play(), connectToTV()
– CHANNEL constant
• TV interface– power(), setChannel(),
getChannel()
• VCR with RF connector– setRGB()
• TV with RF connector interface– getRGB()
• TV with S-Video connector interface– getSVideo()
• VCR RGB– Implements
connectToTV in terms of getRGB()
• VCR SVideo– Implements
connectToTV() in terms of getSVideo()
Electronics Example
• Need for factories– VCR RF goes with TV
RF
– VCR SVideo goes with RV Svideo
• RGB Factory– TV RF and VCR RF
• SVideo Factory– Svideo TVs & VCR
• Need for façade– Want to simulate a single
combo unit
• Methods– Constructor asks vcr to
connect to TV and sets TV channel to vcr’s CHANNEL
– power()• powers both components
– getChannel(), setChannel(), rcord() and play()
• Asks vcr to do the operation