93
Multiple Inheritance, Factories, & Facades Prasun Dewan Comp 114

Multiple Inheritance, Factories, & Facades Prasun Dewan Comp 114

  • View
    220

  • Download
    0

Embed Size (px)

Citation preview

Multiple Inheritance, Factories, & Facades

Prasun Dewan

Comp 114

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();}

}

Factory Pattern

Factory Interface

Factory Class 1 Factory Class 2

implements

Alternative Factory Pattern

Abstract Factory Class

Factory Class 1 Factory Class 2

extends

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

Facade pattern

RegularCourse

FreshmanSeminar

CourseList

Facade

Facade pattern

Component1

Component2

ComponentN

Facade

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