The AccountServerFactory (itself a Factory pattern instance) is responsible for
ID: 3670245 • Letter: T
Question
The AccountServerFactory (itself a Factory pattern instance) is responsible for creating the AccountServer. However, there should only be one AccountServer object in the entire application, but AccountServerFactory does not implement this constraint right now. Refactor AccountServerFactory to implement a full Singleton pattern. Note: You must NOT modify any code outside of AccountServerFactory to get this pattern to work!
public class AccountServerFactory {
public AccountServerFactory() {
}
public IAccountServer getAccountServer() {
return new ServerSolution();
}
}
Explanation / Answer
Main.java
import javax.swing.JFrame;
final class Main {
/**
* Private constructor to address STYLE issue.
*/
private Main() {
}
/**
* All methods should have a Javadoc according to STYLE.
* @param args command-line arguments
* @throws Exception as per typical main specifications
*/
public static void main(final String[] args) throws Exception {
if (args.length != 1) {
System.out.println("Usage: java FormMain <property file>");
System.exit(1);
}
String propertyFile = args[0];
JFrame frame = new MainFrame(propertyFile);
frame.setVisible(true);
}
}
MainFrame.java
import javax.swing.JFrame;
final class Main {
/**
* Private constructor to address STYLE issue.
*/
private Main() {
}
/**
* All methods should have a Javadoc according to STYLE.
* @param args command-line arguments
* @throws Exception as per typical main specifications
*/
public static void main(final String[] args) throws Exception {
if (args.length != 1) {
System.out.println("Usage: java FormMain <property file>");
System.exit(1);
}
String propertyFile = args[0];
JFrame frame = new MainFrame(propertyFile);
frame.setVisible(true);
}
}
Account.java
public abstract class Account implements java.io.Serializable {
private static final long serialVersionUID = 1L;
protected enum State {
OPEN, CLOSED, OVERDRAWN
};
protected float balance = 0.0F;
protected String _name;
private State _state;
protected Account(String n) {
_name = n;
_state = State.OPEN;
}
protected Account(String n, float b) {
this(n);
balance = b;
}
/**
Method: getName()
Inputs:none
Returns:name of the Account
Description:returns the Account
*/
public final String getName() {
return _name;
}
/**
Method: getBalance()
Inputs:none
Returns:balance in the Account
Description:gets the balance of an account
*/
public final float getBalance() {
return balance;
}
/**
Method: deposit()
Inputs:none
Returns:balance in the Account
Description:Adds money to an account. May not be done if the account is CLOSED
@param parameter
amount is a deposit and must be > 0
@return true if the deposit was successful, false if not due to amount or
invalid state
*/
public abstract boolean deposit(float amount);
/**
Method: withdrawl()
Inputs:amount
Returns:Checking or Savings
Description: * Takes money out of an account. If the balance falls below 0 then the
* account is moved to an OVERDRAWN state
*
* @param parameter
* amount is a withdrawal and must be > 0
* @return true if the deposit was successful, false if not due to amount or
* invalid state
*/
public abstract boolean withdraw(float amount);
/**
* @return either "Checking" or "Savings"
*/
/**
Method: getType()
Inputs:none
Returns:type
Description:returns the Type
*/
public abstract String getType();
/**
Method: _getState()
Inputs:none
Returns:state
Description:returns the State
*/
protected final State _getState() {
return _state;
}
/**
Method: _getState()
Inputs:state
Returns:final state
Description:returns the final State
*/
protected final void _setState(State s) {
_state = s;
}
/**
Method: getString()
Inputs:none
Returns:string
Description:converts account name balance and state to string
*/
public String toString() {
return "Account " + _name + " has $" + balance + "and is " + getState()
+ " ";
}
}
AccountServer.java
import java.io.IOException;
import java.util.List;
public interface AccountServer {
/**
Method: _newAccount()
Inputs:type name and balance
Returns:boolean
* Create a new account object in the server. if an account already exists with the given name
* then a new account is not created and stored.
*
@param type must be one of Savings or Checking
@param name leading or trailing whitespace is removed
@param balance must be non-negative
@throws IllegalArgumentException if the account type is invalid or the balance is non-negative.
@return boolean true if the account was created and stored, false otherwise
*/
public boolean newAccount(String type, String name, float balance) throws IllegalArgumentException;
/**
Method: closeAccount()
Inputs:name
Returns:sobect or null
Close an account
@param name leading or trailing whitespace is removed
* @return boolean true if there was an account with this name and close was successful
*/
public boolean closeAccount(String name);
/**
Method: getAccount()
Inputs:name
Returns:list
* @param name name of the account
* @return Account object or null if not found.
*/
public Account getAccount(String name);
/**
Method: getAllAccount(s)
Inputs:name
Returns:a list of accounts
* @return a list of all Accounts inside the server
*/
public List<Account> getAllAccounts();
/**
Method: getActiveAccounts()
Inputs:none
Returns:list of all accounts
* @return a list of Accounts inside the server that are not CLOSED
*/
public List<Account> getActiveAccounts();
/**
Method: saveAccounts()
Inputs:none
Returns:nothing
* Saves the state of the server
* @throws IOException if unable to save the state
*/
public void saveAccounts() throws IOException;
}
AccountServerFactory.java
public class AccountServerFactory {
protected static AccountServerFactory singleton = null;
protected AccountServerFactory() {
}
public static AccountServerFactory getMe() {
if (singleton == null) {
singleton = new AccountServerFactory();
}
return singleton;
}
/**
Method: lookup()
Inputs:none
Returns:serverSolution
Description: looks up ServerSolution
*/
public AccountServer lookup() {
return new ServerSolution();
}
}
Checking.java
public class Checking extends Account {
private static final long serialVersionUID = 11L;
private int numWithdraws = 0;
private Checking(String name) {
super(name);
}
/**
Method:createChecking()
Inputs:name
Returns: new name
Description:Creates checking account
*/
public static Checking createChecking(String name) {
return new Checking(name);
}
public Checking(String name, float balance) {
super(name, balance);
}
/**
Method: desposit()
Inputs:amount
Returns:boolean
Description:A deposit may be made unless the Checking account is closed @param float is the deposit amount
*/
public boolean deposit(float amount) {
if (getState() != State.CLOSED && amount > 0.0f) {
balance = balance + amount;
if (balance >= 0.0f) {
setState(State.OPEN);
}
return true;
}
return false;
}
/**
Method: withdrawl()
Inputs:amount
Returns:boolean
Description:After 10 withdrawals a fee of $2 is charged per transaction You may
* continue to withdraw an overdrawn account until the balance is below -$100
*/
public boolean withdraw(float amount) {
if (amount > 0.0f) {
// KG: incorrect, last balance check should be >=
if (getState() == State.OPEN || (getState() == State.OVERDRAWN && balance > -100.0f)) {
balance = balance - amount;
numWithdraws++;
if (numWithdraws > 10){
balance = balance - 2.0f;
}
if (balance < 0.0f){
setState(State.OVERDRAWN);
}
return true;
}
}
return false;
}
/**
Method: getType()
Inputs:none
Returns:Checking type
Description:returns the Checking type of account
*/
public String getType() { return "Checking"; }
/**
Method: toString()
Inputs:none
Returns:converts the name and balance of checking account to a string
Description:returns the Checking type of account
*/
public String toString() {
return "Checking: " + getName() + ": " + getBalance();
}
}
Savings.java
public class Savings extends Account {
private static final long serialVersionUID = 111L;
private int numWithdraws = 0;
public Savings(String name) {
super(name);
}
public Savings(String name, float balance) throws IllegalArgumentException {
super(name, balance);
}
/**
/**
Method: deposit()
Inputs:amount
Returns:boolean
* Create a new account object in the server. if an account already exists with the given name
* then a new acc
* A deposit comes with a fee of 50 cents per deposit
*/
public boolean deposit(float amount) {
if (getState() != State.CLOSED && amount > 0.0f) {
balance = balance + amount - 0.50F;
if (balance >= 0.0f) {
setState(State.OPEN);
}
}
return false;
}
/**
Method: withdrawl()
Inputs:amount
Returns:boolean
* A withdrawal. After 3 withdrawals a fee of $1 is added to each withdrawal.
* An account whose balance dips below 0 is in an OVERDRAWN state
*/
public boolean withdraw(float amount) {
if (getState() == State.OPEN && amount > 0.0f) {
balance = balance - amount;
numWithdraws++;
if (numWithdraws > 3)
balance = balance - 1.0f;
// KG BVA: should be < 0
if (balance <= 0.0f) {
setState(State.OVERDRAWN);
}
return true;
}
return false;
}
/**
Method: getType()
Inputs:none
Returns:type!
*/
public String getType() { return "Savings"; } //return wrong type
/**
Method: toString()
Inputs:none
Returns:string of name and balance
*/
public String toString() {
return "Savings: " + getName() + ": " + getBalance();
}
}
ServerSolution.java
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.io.*;
class ServerSolution implements AccountServer {
static String fileName = "accounts.ser";
Map<String,Account> accountMap = null;
public ServerSolution() {
accountMap = new HashMap<String,Account>();
File file = new File(fileName);
ObjectInputStream in = null;
try {
if (file.exists()) {
System.out.println("Reading from file " + fileName + "...");
in = new ObjectInputStream(new FileInputStream(file));
Integer sizeI = (Integer) in.readObject();
int size = sizeI.intValue();
for (int i=0; i < size; i++) {
Account acc = (Account) in.readObject();
if (acc != null)
accountMap.put(acc.getName(), acc);
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
}
/**
Method: _newAccountFactory(String type, String name, float balance)
Inputs:String type, String name, float balance
Returns:boolean
Description:checks if account is valid
*/
private boolean _newAccountFactory(String type, String name, float balance)
throws IllegalArgumentException {
if (accountMap.get(name) != null) return false;
Account acc;
if ("Checking".equals(type)) {
acc = new Checking(name, balance);
} else if ("Savings".equals(type)) {
acc = new Savings(name, balance);
} else {
throw new IllegalArgumentException("Bad account type:" + type);
}
try {
accountMap.put(acc.getName(), acc);
} catch (Exception exc) {
return false;
}
return true;
}
/**
Method: newAccount(String type, String name, float balance)
Inputs:String type, String name, float balance
Returns:boolean
Description:creates new account
*/
public boolean newAccount(String type, String name, float balance)
throws IllegalArgumentException {
if (balance < 0.0f) throw new IllegalArgumentException("New account may not be started with a negative balance");
return newAccountFactory(type, name, balance);
}
/**
Method: closeAccount(String name)
Inputs:String name
Returns:boolean
Description:closes an account
*/
public boolean closeAccount(String name) {
Account acc = accountMap.get(name);
if (acc == null) {
return false;
}
acc.setState(State.CLOSED);
return true;
}
/**
Method: getAccount(String name)
Inputs:String name
Returns:Account name
Description:returns the Account
*/
public Account getAccount(String name) {
return accountMap.get(name);
}
/**
Method: getAllAccount()
Inputs:none
Returns:Array List of all the Accounts
Description:returns the Account
*/
public List<Account> getAllAccounts() {
return new ArrayList<Account>(accountMap.values());
}
/**
Method: getActiveAccount()
Inputs:none
Returns:active accounts
Description:returns the Account
*/
public List<Account> getActiveAccounts() {
List<Account> result = new ArrayList<Account>();
for (Account acc : accountMap.values()) {
if (acc.getState() != State.CLOSED) {
result.add(acc);
}
}
return result;
}
/**
Method: saveAccounts()
Inputs:none
Returns: none
Description:saves account
*/
public void saveAccounts() throws IOException {
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(new FileOutputStream(fileName));
out.writeObject(Integer.valueOf(accountMap.size()));
for (int i=0; i < accountMap.size(); i++) {
out.writeObject(accountMap.get(i));
}
} catch (Exception e) {
e.printStackTrace();
throw new IOException("Could not write file:" + fileName);
} finally {
if (out != null) {
try {
out.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
}
}
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.