Talk:Factory
From APIDesign
(Factory instances are more flexible than factory classes) |
|||
Line 2: | Line 2: | ||
Example: | Example: | ||
+ | <source lang="java"> | ||
public enum BankAccountEnum | public enum BankAccountEnum | ||
{ | { | ||
Line 19: | Line 20: | ||
public abstract BankAccount createBankAccount(); | public abstract BankAccount createBankAccount(); | ||
} | } | ||
+ | </source> | ||
Each result instance carries with it a reference to the factory instance that created it. I can directly get the correct factory instance to create a clone. | Each result instance carries with it a reference to the factory instance that created it. I can directly get the correct factory instance to create a clone. | ||
Line 24: | Line 26: | ||
The BankAccount base class can be polymorphically subclassed into SavingsAccount and CheckingAccount, with corresponding subclasses for SavingsAccountFactory and CheckingAccountFactory. | The BankAccount base class can be polymorphically subclassed into SavingsAccount and CheckingAccount, with corresponding subclasses for SavingsAccountFactory and CheckingAccountFactory. | ||
+ | <source lang="java"> | ||
public abstract class CheckingAccount | public abstract class CheckingAccount | ||
extends BankAccount | extends BankAccount | ||
Line 50: | Line 53: | ||
} | } | ||
} | } | ||
+ | </source> | ||
and a similar pair of classes for SavingsAccount. I can keep the factory instances in an array that is indexed by the BankAccountEnum to select the factory that matches the kind of account that I want to create. Or I can wrap the array within a "Factories" class that has methods for obtaining the factory instance or directly creating an instance from a specified BankAccountEnum. | and a similar pair of classes for SavingsAccount. I can keep the factory instances in an array that is indexed by the BankAccountEnum to select the factory that matches the kind of account that I want to create. Or I can wrap the array within a "Factories" class that has methods for obtaining the factory instance or directly creating an instance from a specified BankAccountEnum. | ||
+ | <source lang="java"> | ||
public abstract class BankAccountFactories | public abstract class BankAccountFactories | ||
{ | { | ||
Line 66: | Line 71: | ||
} | } | ||
} | } | ||
+ | </source> | ||
The "Factories" instance can be implemented elsewhere and saved in a global repository for any component to use without knowing anything about the underlying implementation. The use of enum indeces allows for easily extending the polymorphism to future subclasses (e.g., MoneyMarketAccount) without affecting existing clients. | The "Factories" instance can be implemented elsewhere and saved in a global repository for any component to use without knowing anything about the underlying implementation. The use of enum indeces allows for easily extending the polymorphism to future subclasses (e.g., MoneyMarketAccount) without affecting existing clients. |
Current revision
I prefer to use a factory reference type instead of a static factory method. This approach enables polymorphism for the factory result type and a corresponding polymorphism of the factory reference type.
Example:
public enum BankAccountEnum { CHECKING_ACCOUNT, SAVINGS_ACCOUNT; } public abstract class BankAccount { public abstract BankAccountEnum getBankAccountEnum(); public abstract BankAccountFactory getBankAccountFactory(); } public abstract class BankAccountFactory { public abstract BankAccount createBankAccount(); }
Each result instance carries with it a reference to the factory instance that created it. I can directly get the correct factory instance to create a clone.
The BankAccount base class can be polymorphically subclassed into SavingsAccount and CheckingAccount, with corresponding subclasses for SavingsAccountFactory and CheckingAccountFactory.
public abstract class CheckingAccount extends BankAccount { public final BankAccountEnum getBankAccountEnum() { return BankAccountEnum.CHECKING_ACCOUNT; } public abstract CheckingAccountFactory getCheckingAccountFactory(); public final BankAccountFactory getBankAccountFactory() { return getCheckingAccountFactory(); } } public abstract class CheckingAccountFactory extends BankAccountFactory { public abstract CheckingAccount createCheckingAccount(); public final BankAccount createBankAccount() { return createCheckingAccount(); } }
and a similar pair of classes for SavingsAccount. I can keep the factory instances in an array that is indexed by the BankAccountEnum to select the factory that matches the kind of account that I want to create. Or I can wrap the array within a "Factories" class that has methods for obtaining the factory instance or directly creating an instance from a specified BankAccountEnum.
public abstract class BankAccountFactories { public abstract BankAccountFactory getBankAccountFactory(BankAccountEnum theBankAccountEnum); public final BankAccount createBankAccount(BankAccountEnum theBankAccountEnum) { BankAccount result; BankAccountFactory factory; factory = getBankAccountFactory(theBankAccountEnum); result = factory.createBankAccount(); return result; } }
The "Factories" instance can be implemented elsewhere and saved in a global repository for any component to use without knowing anything about the underlying implementation. The use of enum indeces allows for easily extending the polymorphism to future subclasses (e.g., MoneyMarketAccount) without affecting existing clients.
Of course, I use an automated code generator to create the Java source code, so it's easy for me to maintain consistent source code structure throughout the polymorphic pieces.
Two cents worth. Your mileage may vary.