目的
定義可生成物件的介面,但讓子類別決定該實體化哪種類別的物件。讓類別把實體化的程序推遲給子類別去實作。
Define an interface for creating an object, but let the subclass decide which class to instantiate. Here, the word interface means to provide a contract/method to create an object. Factory method lets a class defer instantiation to subclasses. This pattern involves “inheritance.”
適用
- 當類別無法明指想要生成的物件類別時。
- 當類別希望子類別去指定想要生成的物件類型時。
- 將類別將權力下放一個或多個子類別,你又希望將「交付給哪些子類別」的知識集中在一個地方時。
結構及成員
Collaborations: Creator的子類別必須定義Factory Method實體,以回傳適當的Concrete Product物件。
影響結果
好處
平行地位類別階層通常會發生在「類別將某些權責委託給其他類別處理」的情況,如繪圖程式中,特定操弄圖形的動作,如:伸長直線要移動某個端點;伸長圖形可以移動好幾個點;伸長文字方塊要調整行距……因此,需要被Create的Manipulator [註:Manipulator地位同Product] 也會不一樣(以操作為例,在繪圖程式中,不同的繪圖物件要有不同的Manipulator物件處理不同的行為)。
但儘管如此,一個Factory(Figure)仍只能製造一種Product(Minupulator),因此如果要讓一個Factory可以製造多個Product,或多個同Style的Product,詳見 Abstract Factory Pattern。
壞處
實作
兩種主要形式
- Creator是Abstract Class,Factory Method只是空殼。
- Creator是Concrete Class,Factory Method有預設行為。
參數化Factory Method
可傳入參數指明要產生什麼Product。
命名慣例
好的命名慣例會讓Factory Method更一目瞭然。
Example: DBConnection Factory
//Interface: DBConnection
package db.connection;
public interface DBConnection {
void getConnection();
}
//Class: MySQLDBConnection
package db.connection;
public class MySQLDBConnection implements DBConnection {
public void getConnection(){
System.out.println("MySQL DB is connected");
}
}
//Class: JavaDBConnection
package db.connection;
public class JavaDBConnection implements DBConnection{
public void getConnection(){
System.out.println("Java DB is connected");
}
}
//Class: OracleDBConnection
package db.connection;
public class OracleDBConnection implements DBConnection{
public void getConnection(){
System.out.println("Oracle DB is connected");
}
}
//Interface: DBConnectionFactory
package db.connection;
public interface DBConnectionFactory {
DBConnection createConnection();
}
//Interface: MyDBConnectionFactory
package db.connection;
public class MyDBConnectionFactory implements DBConnectionFactory{
private String type;
public MyDBConnectionFactory(String type){
this.type=type;
}
public DBConnection createConnection(){
if (type.equalsIgnoreCase("Oracle")){
return new OracleDBConnection();
} else if (type.equalsIgnoreCase("MySQL")){
return new MySQLDBConnection();
} else if (type.equalsIgnoreCase("JavaDB")){
return new JavaDBConnection();
} else {
//default product
return new OracleDBConnection();
}
}
}
}
//Class: Main
package db.connection;
public class Main {
public static void main(String[] args) {
MyDBConnectionFactory factory = new MyDBConnectionFactory("JavaDB");
factory.createConnection().getConnection();
factory = new MyDBConnectionFactory("MySQL");
factory.createConnection().getConnection();
factory = new MyDBConnectionFactory("Oracle");
factory.createConnection().getConnection();
}
}
Result:
Java DB is connected
MySQL DB is connected
Oracle DB is connected