Abstract Factory Pattern In Java
Join the DZone community and get the full member experience.
Join For FreeIn the continuation of my previous article (Strategy vs. Factory Design Patterns in Java), I am here with an article on Abstract Factory Pattern. In this article, I will try to highlight the usage of the pattern along with the difference with the Factory Pattern.
Abstract Factory Pattern
- The abstract factory pattern is a creational pattern which provides a way to encapsulate a group of individual factories that have a common purpose or theme; without specifying their concrete classes.
- The Abstract Factory patterns work around a super-factory which creates other factories.
- This super-factory is also known as a factory of factories.
- The Abstract Factory pattern is responsible for creating a factory of related objects without explicitly specifying their classes.
- Each generated factory can give the objects as per the Factory pattern.
- So in short, Abstract factory provides an interface to create different concrete factories. Each such factory works with a family or group objects. and hence Abstract factory provides a way to work with multiple such factories. So, we can also call it as factory of factories.
As we can see in the above class diagram, there is a car factory which is in business for ages. So it has an old car factory called ClassicCarFactory. Later, the company started manufacturing some new modern cars and hence started another factory called ModernCarFactory. So, for the that, we used AbtractCarFactory as Abstract Factory Design Pattern. In that way, we will make sure to have no or minimum changes on the client end.
Suppose by the success in the modern cars, the company decided to also start manufacturing the sports cars and started another factory for that, the design will be as below by using the same pattern.
So, the Abstract Factory design pattern solves problems like:
- How can an application be independent of how its objects are created?
- How can a class be independent of how the objects it requires are created?
- How can families of related or dependent objects be created?
To make it easy to understand and to highlight similarities and differences with Factory Pattern, I am using the same example of Account Management what I took in the article Strategy vs. Factory Design Patterns in Java.
In the example, I only did some re-structuring/packaging to make code more cleaner and easy to understand. May be its not best example to list here. But my intention is to show the implementation and use of the Abstract Factory and not any other accounting system. So, please excuse if it does not look good to you.
Account-Management Example Using the Abstract Factory Pattern
We have the AccountType
interface to define account-types with the pre-defined or fixed rate of interest. Here, I have added more account types to make use or more Factory Classes.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct;
public enum AccountType {
SAVING(2.0d), CURRENT(1.0d), HOME_LOAN(3.0d), VEHICLE_LOAN(4.0d), PERSONAL_LOAN(5.0d), RECURRING_DEPOSIT(2.5d), FIXED_DEPOSIT(3.5d);
private double rate;
AccountType(final double rate) {
this.rate = rate;
}
public double getRate() {
return rate;
}
}
I am implementing an abstract base class for the account and creating the various flavors of Account
by sub-classing it.
Below is the code for the Account
. Please note that I have defined the class as abstract
to force the sub-classing of it.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct;
public abstract class Account {
protected long accountNo;
protected String accountHolderName;
protected AccountType accountType;
protected InterestStrategy interestStrategy;
protected double amount;
public Account() {
super();
}
public Account(long accountNo, String accountHolderName, AccountType accountType) {
this();
this.accountNo = accountNo;
this.accountHolderName = accountHolderName;
this.accountType = accountType;
}
public long getAccountNo() {
return accountNo;
}
public void setAccountNo(long accountNo) {
this.accountNo = accountNo;
}
public String getAccountHolderName() {
return accountHolderName;
}
public void setAccountHolderName(String accountHolderName) {
this.accountHolderName = accountHolderName;
}
public AccountType getAccountType() {
return accountType;
}
public void setAccountType(AccountType accountType) {
this.accountType = accountType;
}
public InterestStrategy getInterestStrategy() {
return interestStrategy;
}
public void setInterestStrategy(InterestStrategy interestStrategy) {
this.interestStrategy = interestStrategy;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public void deposit(double amount) {
// check for only positive/valid amount
if (amount > 0.0d) {
this.amount += amount;
}
}
public void withdraw(double amount) {
// check for only positive/valid amount and also for below than the available
// amount in account
if (amount > 0.0d && amount < this.amount) {
this.amount -= amount;
}
}
public abstract double getInterest(int term);
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Account [accountNo=").append(getAccountNo()).append(", accountHolderName=")
.append(getAccountHolderName()).append(", accountType=").append(getAccountType()).append(", rate=")
.append((getAccountType() != null) ? getAccountType().getRate() : 0.0d).append(", interestStrategy=")
.append(getInterestStrategy().getName()).append(", amount=").append(getAmount()).append("]");
return builder.toString();
}
}
In this example, since the we are gonna create many sub-types of Account
class, I am writing a new enum InterestStrategy
to provide interest calculation algorithms.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct;
public enum InterestStrategy {
SIMPLE ("Simple Interest") {
public double getInterest(AccountType accountType, double amount, int term) {
if (accountType != null) {
return ((amount * term * accountType.getRate()) / 100);
}
return 0.0d;
}
},
COMPOUND ("Compound Interest") {
public double getInterest(AccountType accountType, double amount, int term) {
if (accountType != null) {
return amount * Math.pow(1.0 + accountType.getRate() / 100.0, term) - amount;
}
return 0.0d;
}
};
private String name;
InterestStrategy(String name) {
this.name = name;
}
public abstract double getInterest(AccountType accountType, double amount, int term);
public String getName() {
return name;
}
}
Now, we have to create the types for the account. I create the SavingAccount
, which is tied up with the compound interest algorithm.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct.saving;
import org.trishinfotech.abstractfactory.acct.Account;
import org.trishinfotech.abstractfactory.acct.AccountType;
import org.trishinfotech.abstractfactory.acct.InterestStrategy;
public class SavingAccount extends Account {
public SavingAccount(long accountNo, String accountHolderName) {
super(accountNo, accountHolderName, AccountType.SAVING);
setInterestStrategy(InterestStrategy.COMPOUND);
}
public double getInterest(int term) {
return this.getInterestStrategy().getInterest(accountType, amount, term);
}
}
You can compare the above code of SavingAccount with the code in the article Strategy vs. Factory Design Patterns in Java to understand the use of enum. And to understand the code written inside of enum you may refer to my article Java Enums: How to Make Enums More Useful.
Next, I created the CurrentAccount
, which is tied up with the simple-interest algorithm.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct.saving;
import org.trishinfotech.abstractfactory.acct.Account;
import org.trishinfotech.abstractfactory.acct.AccountType;
import org.trishinfotech.abstractfactory.acct.InterestStrategy;
public class CurrentAccount extends Account {
public CurrentAccount(long accountNo, String accountHolderName) {
super(accountNo, accountHolderName, AccountType.CURRENT);
setInterestStrategy(InterestStrategy.SIMPLE);
}
public double getInterest(int term) {
return this.getInterestStrategy().getInterest(accountType, amount, term);
}
}
So, basically, the types of accounts not only have pre-defined rates (as in the strategy) but also the pre-defined interest calculation algorithms, which are tightly coupled. Therefore, the account instance will have defined functionality.
Because the above two accounts SavingAccount
and CurrentAccount
are type of saving, I put them into a sub-package called saving. This is something I did just to organize the code and there is no relation of this with the design pattern I am discussing here.
Now, I will write more concrete sub-classes of Account
to represent each of the AccountType
we have created.
Below is the code of LoanAccount
, which is an abstract class and a sub-type of Account. I made it abstract just to have different flavors of loan-types like Home Loan, Vehicle Loan or Personal Loan.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct.loan;
import org.trishinfotech.abstractfactory.acct.Account;
import org.trishinfotech.abstractfactory.acct.AccountType;
public abstract class LoanAccount extends Account {
protected int termInMonths;
public LoanAccount(long accountNo, String accountHolderName, AccountType accountType, int termInMonths) {
super(accountNo, accountHolderName, accountType);
this.termInMonths = termInMonths;
}
// since its a loan account, reversing the withdraw and deposit to make it responsibility
// just to keep the example as simple as possible
public void deposit(double amount) {
super.withdraw(amount);
}
public void withdraw(double amount) {
super.deposit(amount);
}
public int getTermInMonths() {
return termInMonths;
}
public void setTermInMonths(int termInMonths) {
this.termInMonths = termInMonths;
}
}
So with LoanAccount
sub-class, I placed all of the common code I needed to operate any kind of loan account like any loan requires a term to clear. Also, because I like to avoid the much of the coding, I reversed the deposit and withdraw with respect to amount. I mean deposit in loan means clearing the amount and withdraw from loan means a kind of disbursement of the amount to the builder of the home or the vehicle supplier.
To organize the loan related code, I use loan as a sub-package.
Now I created HomeLoanAccount
, which is tied up with the compound-interest algorithm.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct.loan;
import org.trishinfotech.abstractfactory.acct.AccountType;
import org.trishinfotech.abstractfactory.acct.InterestStrategy;
public class HomeLoanAccount extends LoanAccount {
public HomeLoanAccount(long accountNo, String accountHolderName, int termInMonths) {
super(accountNo, accountHolderName, AccountType.HOME_LOAN, termInMonths);
setInterestStrategy(InterestStrategy.COMPOUND);
}
public double getInterest(int term) {
return this.getInterestStrategy().getInterest(accountType, amount, term);
}
}
Next I created VehicleLoanAccount
, which is tied up with the compound-interest algorithm.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct.loan;
import org.trishinfotech.abstractfactory.acct.AccountType;
import org.trishinfotech.abstractfactory.acct.InterestStrategy;
public class VehicleLoanAccount extends LoanAccount {
public VehicleLoanAccount(long accountNo, String accountHolderName, int termInMonths) {
super(accountNo, accountHolderName, AccountType.VEHICLE_LOAN, termInMonths);
setInterestStrategy(InterestStrategy.COMPOUND);
}
public double getInterest(int term) {
return this.getInterestStrategy().getInterest(accountType, amount, term);
}
}
Next I created PersonalLoanAccount
, which is tied up with the compound-interest algorithm.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct.loan;
import org.trishinfotech.abstractfactory.acct.AccountType;
import org.trishinfotech.abstractfactory.acct.InterestStrategy;
public class PersonalLoanAccount extends LoanAccount {
public PersonalLoanAccount(long accountNo, String accountHolderName, int termInMonths) {
super(accountNo, accountHolderName, AccountType.PERSONAL_LOAN, termInMonths);
setInterestStrategy(InterestStrategy.COMPOUND);
}
public double getInterest(int term) {
return this.getInterestStrategy().getInterest(accountType, amount, term);
}
}
Similarly for deposit type of account, I use sub-package called deposit to organize the code.
Below is the code of DepositAccount
where I placed all of the common code I needed to operate any kind of deposit account like there is restriction on amount and number of withdraw and deposit.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct.deposit;
import org.trishinfotech.abstractfactory.acct.Account;
import org.trishinfotech.abstractfactory.acct.AccountType;
public abstract class DepositAccount extends Account {
protected int termInMonths;
private boolean withdrawDone;
public DepositAccount(long accountNo, String accountHolderName, AccountType accountType, int termInMonths) {
super(accountNo, accountHolderName, accountType);
this.termInMonths = termInMonths;
}
public int getTermInMonths() {
return termInMonths;
}
public void setTermInMonths(int termInMonths) {
this.termInMonths = termInMonths;
}
public void withdraw(double amount) {
// ignore the given amount since we can withdraw whole amount at the maturity
if (!withdrawDone && this.amount > 0.0d) {
this.amount = 0.0d;
withdrawDone = true;
} else {
System.out.println("Sorry! We can withdraw whole amount only once from a Deposit Account!");
}
}
}
Next I created FixedDepositAccount
, which is tied up with the simple-interest algorithm.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct.deposit;
import org.trishinfotech.abstractfactory.acct.AccountType;
import org.trishinfotech.abstractfactory.acct.InterestStrategy;
public class FixedDepositAccount extends DepositAccount {
private boolean depositDone;
public FixedDepositAccount(long accountNo, String accountHolderName, int termInMonths) {
super(accountNo, accountHolderName, AccountType.FIXED_DEPOSIT, termInMonths);
setInterestStrategy(InterestStrategy.SIMPLE);
}
public double getInterest(int term) {
return this.getInterestStrategy().getInterest(accountType, amount, term);
}
public void deposit(double amount) {
if (!depositDone && amount > 0.0d) {
this.amount = amount;
depositDone = true;
} else {
System.out.println("Sorry! We can deposit only once in a Fixed Deposit Account!");
}
}
}
Next I created RecurringDepositAccount
, which is tied up with the compound-interest algorithm.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct.deposit;
import org.trishinfotech.abstractfactory.acct.AccountType;
import org.trishinfotech.abstractfactory.acct.InterestStrategy;
public class RecurringDepositAccount extends DepositAccount {
public RecurringDepositAccount(long accountNo, String accountHolderName, int termInMonths) {
super(accountNo, accountHolderName, AccountType.RECURRING_DEPOSIT, termInMonths);
setInterestStrategy(InterestStrategy.COMPOUND);
}
public double getInterest(int term) {
return this.getInterestStrategy().getInterest(accountType, amount, term);
}
}
So now we are ready with all the flavors of account we are gonna support in the application.
As we have noticed that we have 3 categories of Account
sub-types as below:
Saving
(in package saving)- SavingAccount
- CurrentAccount
Loan
(in package loan)- LoanAccount
- HomeLoanAccount
- VehicleLoanAccount
- PersonalLoanAccount
- LoanAccount
Deposit
(in package deposit)- DepositAccount
- FixedDepositAccount
- RecurringDepositAccount
- DepositAccount
Now, its time to do Step 1 to implement Abstract Factory for the design pattern we are discussing. We can create AbstractFactory as interface (to server multiple inheritence in java) or as abstract class. Both approach are OK.
Step 1: Here I am creating it as abstract class AbstractAccountFactory
:
xxxxxxxxxx
package org.trishinfotech.abstractfactory;
import org.trishinfotech.abstractfactory.acct.Account;
import org.trishinfotech.abstractfactory.acct.AccountOpeningDetails;
public abstract class AbstractAccountFactory {
public abstract Account createAccount(AccountOpeningDetails opendingDetails);
}
Please note that the abstract method inside factory class returns the highest-level of the account class/interface to show that all the concrete implementation of factory will have a same purpose or theme. Here, I also changed multiple parameters to a single POJO class called AccountOpendingDetails
. This is to avoid lengthy parameter list as well as validating parameter values
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct;
public class AccountOpeningDetails {
private long accountNo;
private String accountHolderName;
private AccountType accountType;
private int termInMonths;
public AccountOpeningDetails(long accountNo, String accountHolderName, AccountType accountType) {
super();
this.accountNo = accountNo;
this.accountHolderName = accountHolderName;
this.accountType = accountType;
}
public AccountOpeningDetails(long accountNo, String accountHolderName, AccountType accountType, int termInMonths) {
this(accountNo, accountHolderName, accountType);
this.termInMonths = termInMonths;
}
public long getAccountNo() {
return accountNo;
}
public void setAccountNo(long accountNo) {
this.accountNo = accountNo;
}
public String getAccountHolderName() {
return accountHolderName;
}
public void setAccountHolderName(String accountHolderName) {
this.accountHolderName = accountHolderName;
}
public AccountType getAccountType() {
return accountType;
}
public void setAccountType(AccountType accountType) {
this.accountType = accountType;
}
public int getTermInMonths() {
return termInMonths;
}
public void setTermInMonths(int termInMonths) {
this.termInMonths = termInMonths;
}
public boolean isNotValid(boolean requiredTermInMonths) {
return (accountNo <= 0l || accountHolderName == null || accountHolderName.trim().isEmpty()
|| accountType == null || (requiredTermInMonths ? termInMonths > 0 : false));
}
}
You can see that the AccountOpeningDetails
deals with the same parameters as fields and provides the validation on that as well. This is just for simplicity of the code.
Step 2: Now, let's take a look at the most important step. We have to define the factory class (AccountFactory
) for the Account
based on the given saving account-type i.e SAVING and CURRENT. I am placing the class into the same package of the class which the factory deals with i.e. saving; again just for organizing the code.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct.saving;
import org.trishinfotech.abstractfactory.AbstractAccountFactory;
import org.trishinfotech.abstractfactory.acct.Account;
import org.trishinfotech.abstractfactory.acct.AccountOpeningDetails;
import org.trishinfotech.abstractfactory.acct.AccountType;
public class AccountFactory extends AbstractAccountFactory {
public Account createAccount(AccountOpeningDetails openingDetails) {
if (openingDetails == null || openingDetails.isNotValid(false)) {
throw new IllegalArgumentException("Account Opening Details are not valid!");
}
Account account = null;
AccountType type = openingDetails.getAccountType();
switch (type) {
case SAVING:
account = new SavingAccount(openingDetails.getAccountNo(), openingDetails.getAccountHolderName());
break;
case CURRENT:
account = new CurrentAccount(openingDetails.getAccountNo(), openingDetails.getAccountHolderName());
break;
default:
System.err.println("Unknown/unsupported account-type.");
}
return account;
}
}
Please note that the AccountFactory
is now a sub-type/implementation of the AbstractAccountFactory
.
Next I created LoanAccountFactory
for the AccountType
HOME_LOAN
, VEHICLE_LOAN
, and PERSONAL_LOAN
and placed under that package loan.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct.loan;
import org.trishinfotech.abstractfactory.AbstractAccountFactory;
import org.trishinfotech.abstractfactory.acct.AccountOpeningDetails;
import org.trishinfotech.abstractfactory.acct.AccountType;
public class LoanAccountFactory extends AbstractAccountFactory {
public LoanAccount createAccount(AccountOpeningDetails openingDetails) {
if (openingDetails == null || openingDetails.isNotValid(true)) {
throw new IllegalArgumentException("Account Opening Details are not valid!");
}
LoanAccount account = null;
AccountType type = openingDetails.getAccountType();
switch (type) {
case PERSONAL_LOAN:
account = new PersonalLoanAccount(openingDetails.getAccountNo(), openingDetails.getAccountHolderName(),
openingDetails.getTermInMonths());
break;
case HOME_LOAN:
account = new HomeLoanAccount(openingDetails.getAccountNo(), openingDetails.getAccountHolderName(),
openingDetails.getTermInMonths());
break;
case VEHICLE_LOAN:
account = new VehicleLoanAccount(openingDetails.getAccountNo(), openingDetails.getAccountHolderName(),
openingDetails.getTermInMonths());
break;
default:
System.err.println("Unknown/unsupported account-type.");
}
return account;
}
}
And I created DepositAccountFactory
for AccountType
FIXED_DEPOSIT
and RECURRING_DEPOSIT
and placed under the package deposit.
xxxxxxxxxx
package org.trishinfotech.abstractfactory.acct.deposit;
import org.trishinfotech.abstractfactory.AbstractAccountFactory;
import org.trishinfotech.abstractfactory.acct.AccountOpeningDetails;
import org.trishinfotech.abstractfactory.acct.AccountType;
public class DepositAccountFactory extends AbstractAccountFactory {
public DepositAccount createAccount(AccountOpeningDetails openingDetails) {
if (openingDetails == null || openingDetails.isNotValid(true)) {
throw new IllegalArgumentException("Account Opening Details are not valid!");
}
DepositAccount account = null;
AccountType type = openingDetails.getAccountType();
switch (type) {
case RECURRING_DEPOSIT:
account = new RecurringDepositAccount(openingDetails.getAccountNo(), openingDetails.getAccountHolderName(), openingDetails.getTermInMonths());
break;
case FIXED_DEPOSIT:
account = new FixedDepositAccount(openingDetails.getAccountNo(), openingDetails.getAccountHolderName(), openingDetails.getTermInMonths());
break;
default:
System.err.println("Unknown/unsupported account-type.");
}
return account;
}
}
So, we have three concrete implementation of factories as below:
AccountFactory
- for SAVING family of Account classes.LoanAccountFactory
- for LOAN family of Account classes.DepositAccountFactory
- for DEPOSIT family of Account classes.
Now, we need a provider or producer class which will give us the factory class depending upon our category or family selection. So, here is the code of AccountFactoryProvider
to do that:
xxxxxxxxxx
package org.trishinfotech.abstractfactory;
import org.trishinfotech.abstractfactory.acct.deposit.DepositAccountFactory;
import org.trishinfotech.abstractfactory.acct.loan.LoanAccountFactory;
import org.trishinfotech.abstractfactory.acct.saving.AccountFactory;
public class AccountFactoryProvider {
public static AbstractAccountFactory getAccountFactory(String accountCategory) {
AbstractAccountFactory accountFactory = null;
if (accountCategory != null) {
switch (accountCategory) {
case "SAVING":
accountFactory = new AccountFactory();
break;
case "LOAN":
accountFactory = new LoanAccountFactory();
break;
case "DEPOSIT":
accountFactory = new DepositAccountFactory();
break;
default:
break;
}
}
return accountFactory;
}
}
That's it. Its time to write a Main
program to execute the code and test the output:
xxxxxxxxxx
package org.trishinfotech.abstractfactory;
import org.trishinfotech.abstractfactory.acct.Account;
import org.trishinfotech.abstractfactory.acct.AccountOpeningDetails;
import org.trishinfotech.abstractfactory.acct.AccountType;
public class Main {
public static void main(String[] args) {
AbstractAccountFactory factory = AccountFactoryProvider.getAccountFactory("SAVING");
Account acct1 = factory.createAccount(new AccountOpeningDetails(12345678l, "Vijay Kumar", AccountType.SAVING));
acct1.deposit(10000.0d);
System.out.print(acct1);
System.out.printf(" has interest : %10.2f\n", acct1.getInterest(5));
Account acct2 = factory.createAccount(new AccountOpeningDetails(12345680l, "Jay Kumar", AccountType.CURRENT));
acct2.deposit(10000.0d);
System.out.print(acct2);
System.out.printf(" has interest : %10.2f\n", acct2.getInterest(5));
factory = AccountFactoryProvider.getAccountFactory("DEPOSIT");
Account acct3 = factory.createAccount(new AccountOpeningDetails(12345681l, "Micheal", AccountType.FIXED_DEPOSIT));
acct3.deposit(10000.0d);
System.out.print(acct3);
System.out.printf(" has interest : %10.2f\n", acct3.getInterest(5));
Account acct4 = factory.createAccount(new AccountOpeningDetails(12345682l, "Kim", AccountType.RECURRING_DEPOSIT));
acct4.deposit(10000.0d);
System.out.print(acct4);
System.out.printf(" has interest : %10.2f\n", acct4.getInterest(5));
factory = AccountFactoryProvider.getAccountFactory("LOAN");
Account acct5 = factory.createAccount(new AccountOpeningDetails(12345683l, "Racheal", AccountType.HOME_LOAN));
acct5.withdraw(10000.0d);
System.out.print(acct5);
System.out.printf(" has interest : %10.2f\n", acct5.getInterest(5));
Account acct6 = factory.createAccount(new AccountOpeningDetails(12345685l, "Martin", AccountType.VEHICLE_LOAN));
acct6.withdraw(10000.0d);
System.out.print(acct6);
System.out.printf(" has interest : %10.2f\n", acct6.getInterest(5));
Account acct7 = factory.createAccount(new AccountOpeningDetails(12345686l, "Mike", AccountType.PERSONAL_LOAN));
acct7.withdraw(10000.0d);
System.out.print(acct7);
System.out.printf(" has interest : %10.2f\n", acct7.getInterest(5));
}
}
And here the the output of the program:
Account [accountNo=12345678, accountHolderName=Vijay Kumar, accountType=SAVING, rate=2.0, interestStrategy=Compound Interest, amount=10000.0] has interest : 1040.81
Account [accountNo=12345680, accountHolderName=Jay Kumar, accountType=CURRENT, rate=1.0, interestStrategy=Simple Interest, amount=10000.0] has interest : 500.00
Account [accountNo=12345681, accountHolderName=Micheal, accountType=FIXED_DEPOSIT, rate=3.5, interestStrategy=Simple Interest, amount=10000.0] has interest : 1750.00
Account [accountNo=12345682, accountHolderName=Kim, accountType=RECURRING_DEPOSIT, rate=2.5, interestStrategy=Compound Interest, amount=10000.0] has interest : 1314.08
Account [accountNo=12345683, accountHolderName=Racheal, accountType=HOME_LOAN, rate=3.0, interestStrategy=Compound Interest, amount=10000.0] has interest : 1592.74
Account [accountNo=12345685, accountHolderName=Martin, accountType=VEHICLE_LOAN, rate=4.0, interestStrategy=Compound Interest, amount=10000.0] has interest : 2166.53
Account [accountNo=12345686, accountHolderName=Mike, accountType=PERSONAL_LOAN, rate=5.0, interestStrategy=Compound Interest, amount=10000.0] has interest : 2762.82
I hope this tutorial helped demonstrate the business context and technical implementation of the Abstract Factory Pattern.
Source Code can be found here: Abstract-Factory-Design-Pattern-Sample-Code
Liked the article? Please don't forget to press that like button. Happy coding!
Need more articles, please visit my profile: Brijesh Saxena
Opinions expressed by DZone contributors are their own.
Comments