300 likes | 392 Views
Comp 401 Factories. Instructor: Prasun Dewan. Prerequisite. Inheritance Abstract Classes Inheritance Virtual Abstract Factory Methods. Implementation-Independent Code. How to write code that is independent of a specific implementation?. Interface-based Code.
E N D
Comp 401Factories Instructor: PrasunDewan
Prerequisite • Inheritance Abstract Classes • Inheritance Virtual Abstract Factory Methods
Implementation-Independent Code • How to write code that is independent of a specific implementation?
Interface-based Code publicclassACourseListimplementsCourseList { finalint MAX_SIZE = 50; Course[] contents = new Course[MAX_SIZE]; int size = 0; int size() {returnsize; } booleanisFull() {returnsize == MAX_SIZE; } publicvoidaddElement(Course element) { if (isFull()) System.out.println("Adding item to a full collection"); else { contents[size] = element; size++; } }
Class-Based Code staticCourseList courses = newACourseList(); staticvoidfillCourses() { courses.addElement(newARegularCourse ("Intro. Prog.", "COMP", 14)); courses.addElement(newARegularCourse ("Found. of Prog.", "COMP", 114)); courses.addElement(new AFreshmanSeminar(“Comp. Animation", "COMP")); courses.addElement(new AFreshmanSeminar("Lego Robots", "COMP")); } Repetition staticCourseList courses = newACourseList(); staticvoidfillCourses() { courses.addElement( newALoggedRegularCourse("Intro. Prog.", "COMP", 14)); courses.addElement( newALoggedRegularCourse("Found. of Prog.", "COMP", 114)); courses.addElement( new ALoggedFreshmanSeminar(“Comp. Animation", "COMP")); courses.addElement( new ALoggedFreshmanSeminar("Lego Robots", "COMP")); }
Code Sharing • How to increase code sharing among classes instantiating classes implementing the same interface
Inconsistency in Class-Dependent Code staticCourseList courses = newACourseList(); staticvoidfillCourses() { courses.addElement( newALoggedRegularCourse("Intro. Prog.", "COMP", 14)); courses.addElement( newALoggedRegularCourse("Found. of Prog.", "COMP", 114)); courses.addElement( new ALoggedFreshmanSeminar(“Comp. Animation", "COMP")); courses.addElement( new AFreshmanSeminar("Lego Robots", "COMP")); }
Inconsistency • How to make sure incompatible courses are not added to course list • AFreshmanSeminar • ALoggedRegularCourse
Easy Switching to Logged Versions and Back? staticCourseList courses = newACourseList(); staticvoidfillCourses() { courses.addElement(newARegularCourse ("Intro. Prog.", "COMP", 14)); courses.addElement(newARegularCourse ("Found. of Prog.", "COMP", 114)); courses.addElement(new AFreshmanSeminar(“Comp. Animation", "COMP")); courses.addElement(new AFreshmanSeminar("Lego Robots", "COMP")); } Course parseRegularCourse () { String title = readString(); String dept = readString(); int number = readInt(); returnnewARegularCourse (title, dept, number); } Course parseFreshmanSeminar () { String title = readString(); String dept = readString(); returnnewAFreshmanSeminar(title, dept); }
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
The Problems How to increase sharing between code instantiating different implementations of the same interface? How to prevent instantiation of incompatible implementations? How to allow easy switching between different alternative implementations How to make main and other classes instantiating implementations oblivious to which implementations are used
Factory class • A class that instantiates other classes • 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 publicinterfaceCourseFactory { publicRegularCourse getRegularCourse(String theTitle, String theDept, inttheCourseNum); publicFreshmanSeminar getFreshmanSeminar(String theTitle, String theDept); } Constructors are replaced with object creation methods that take instantiation parameters
ACourseFactory publicclassACourseFactoryimplementsCourseFactory { publicRegularCoursegetRegularCourse (String theTitle, String theDept,inttheCourseNum) { returnnewARegularCourse(theTitle, theDept, theCourseNum); } publicFreshmanSeminargetFreshmanSeminar (String theTitle, String theDept) { returnnewAFreshmanSeminar(theTitle, theDept); } }
ALoggedCourseFactory publicclassALoggedCourseFactoryimplementsCourseFactory { publicLoggedRegularCoursegetRegularCourse (String theTitle, String theDept,inttheCourseNum) { returnnewALoggedRegularCourse (theTitle, theDept, theCourseNum); } publicLoggedFreshmanSeminargetFreshmanSeminar (String theTitle, String theDept) { returnnewALoggedFreshmanSeminar(theTitle, theDept); } } Class can return value of more specific type publicinterfaceCourseFactory { publicRegularCourse getRegularCourse(String theTitle, String theDept, inttheCourseNum); publicFreshmanSeminar getFreshmanSeminar(String theTitle, String theDept); }
Factory-Based Instantiation Factory Factory instantiates a set of related types void create1(…) void create2(…) Provides a method for creating each type of object Each method takes instantiation parameters implements AFactory AnotherFactory Different implementations can instantiate different classes Typically instantiation parameters become constructor parameters How to choose between different factories?
Regular vs. Factory based Instantiation staticvoidfillCourses() { courses.addElement(newARegularCourse ("Intro. Prog.", "COMP", 14)); courses.addElement(newARegularCourse ("Found. of Prog.", "COMP", 114)); courses.addElement(new AFreshmanSeminar(“Comp. Animation", "COMP")); courses.addElement(new AFreshmanSeminar("Lego Robots", "COMP")); } protectedstaticvoidfillCoursesWithFactories() { CourseFactorycourseFactory = newACourseFactory(); courses.addElement(courseFactory.getRegularCourse ("Intro. Prog.", "COMP", 14)); courses.addElement(courseFactory.getRegularCourse ("Found. of Prog.", "COMP", 114)); courses.addElement(courseFactory.getFreshmanSeminar ("Comp. Animation", "COMP")); courses.addElement(courseFactory.getFreshmanSeminar ("Lego Robots", "COMP")); }
Factory Transparent Main? • How to create same main and other course users for different configurations? • Need AbstractFactory to select factories • Only class changed to select different configurations • Main and other classes call abstract factory class
Abstract Factories Factory Selector static Factory getFactory() General Idea Helps choose between factories static setFactory(Factory f) static create1(…) Has a link to a Factory instance static create2(…) Static methods to change and get reference Has-A Can get reference to factory and invoke factory methods Abstract factory provides static versions of factory creation methods for convenience Factory create1(…) create2(…)
Course Abstract Factory publicclassCourseFactorySelector { staticCourseFactorycourseFactory = newACourseFactory(); publicstaticCourseFactorygetCourseFactory() { returncourseFactory; } publicstaticvoidsetCourseFactory(CourseFactorycourseFactory) { CourseFactorySelector.courseFactory= courseFactory; } publicstaticRegularCoursegetRegularCourse (String theTitle, String theDept, inttheCourseNum) { returncourseFactory.getRegularCourse (theTitle, theDept, theCourseNum); } publicstaticFreshmanSeminargetFreshmanSeminar (String theTitle, String theDept) { returncourseFactory.getFreshmanSeminar(theTitle, theDept); } }
Regular vs. Abstract Factory based Instantiation staticvoidfillCourses() { courses.addElement(newARegularCourse ("Intro. Prog.", "COMP", 14)); courses.addElement(newARegularCourse ("Found. of Prog.", "COMP", 114)); courses.addElement(new AFreshmanSeminar(“Comp. Animation", "COMP")); courses.addElement(new AFreshmanSeminar("Lego Robots", "COMP")); } protectedstaticvoidfillCoursesWithFactories() { courses.addElement(CourseFactorySelecto.getRegularCourse ("Intro. Prog.", "COMP", 14)); courses.addElement(CourseFactorySelector.getRegularCourse ("Found. of Prog.", "COMP", 114)); courses.addElement(CourseFactorySelector.getFreshmanSeminar ("Comp. Animation", "COMP")); courses.addElement(CourseFactorySelector.getFreshmanSeminar ("Lego Robots", "COMP")); }
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 • Car Analogy • Dealership selling you cars and accessories that go with them.
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
Factory Practical Examples • 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!
ObjectEditor Factory Example package bus.uigen.view; import java.awt.Container; publicinterface PanelFactory { public Container createPanel (); }
ObjectEditor Factory Selector Example package bus.uigen.view; import java.awt.Container; publicclass PanelSelector { //static PanelFactory factory = new SwingPanelFactory(); static PanelFactory factory = new AWTPanelFactory(); publicstaticvoid setPanelFactory (PanelFactory newVal) { factory = newVal; } publicstatic Container createPanel() { return factory.createPanel(); } }
Java Example LineBorderblackline= BorderFactory.createLineBorder(Color.black); LineBorderblackline= newLineBorder(Color.black); Factory can return a single instance of LineBorder for all black line borders
Factory uses Sharing between code instantiating different implementations of the same interface? Prevent instantiation of incompatible implementations Easy switching between different alternative implementations Sharing of instances among different pieces of code