Reputation: 42730
Currently, I have the following design in my application, which is using enum
as a memory efficient constant
public enum Board {
Toronto // Toronto stock Exchange
}
public class Stock {
private final Board board;
private final Code code;
....
}
This is a memory efficient way. As, if there is thousands of Stock
in a stock exchange, only 1 instance of Board
will be created.
Stock stock0 = new Stock(Code.newInstance("AAA.TO"), Board.Toronto);
Stock stock1 = new Stock(Code.newInstance("AAB.TO"), Board.Toronto);
However, this certainly has some shortcoming. From time-to-time, stock exchange will introduce new board. When such event occurs, I need to
Board
public enum Board {
Toronto, // Toronto stock Exchange
TSXV // New Toronto venture
}
Stock stock0 = new Stock(Code.newInstance("AAA.TO"), Board.Toronto);
Stock stock1 = new Stock(Code.newInstance("AAB.TO"), Board.Toronto);
Stock stock2 = new Stock(Code.newInstance("TRU.V"), Board.TSXV);
I want to avoid such inconvenient. My initial plan is
public class Board {
private final String board;
private Board(String board) {
this.board = board;
}
public Board newInstance(String board) {
return new Board(board);
}
}
However, this is not an memory efficient way. As, multiple instances of Board
will be created.
// 2 Toronto board instance will be created! Not memory efficient when we have huge stock list.
Stock stock0 = new Stock(Code.newInstance("AAA.TO"), Board.newInstance("Toronto"));
Stock stock1 = new Stock(Code.newInstance("AAB.TO"), Board.newInstance("Toronto"));
Stock stock2 = new Stock(Code.newInstance("TRU.V"), Board.newInstance("TSXV"));
I was wondering, what kind of data structure I can apply, so that I can have a memory efficient way to represent constant (In my context, it means the Board
class)
I prefer not to use String
, as I prefer to have type safe, to differentiate among Board
and real String
.
Upvotes: 0
Views: 74
Reputation: 42730
This a thread safe way for doing so. I'm not really sure whether such implementation can considered as Flyweight pattern. However, I had tried my best effort to ensure it is thread safe. If you found any possible fault, feel free to amend the code.
import java.util.concurrent.ConcurrentHashMap;
/**
*
* @author yccheok
*/
public class Board {
private Board(String board) {
this.board = board;
}
public static Board newInstance(String board) {
if (board == null) {
throw new java.lang.IllegalArgumentException("board cannot be null");
}
Board result = map.get(board);
if (result == null) {
final Board instance = new Board(board);
result = map.putIfAbsent(board, instance);
if (result == null) {
return instance;
}
}
assert(result != null);
return result;
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + board.hashCode();
return result;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Board)) {
return false;
}
return this.board.equals(((Board)o).board);
}
@Override
public String toString() {
return board;
}
// Avoid using interface. We want it to be fast!
private static final ConcurrentHashMap<String, Board> map = new ConcurrentHashMap<>();
private final String board;
}
Upvotes: 1
Reputation: 4358
In my opinion, the best solution is to add Board to your database and you have to update your database when the business side raises a new board,your Board may changes day by day to adapt business requirements so it's not suitable for Constant or Enum
Upvotes: 0
Reputation: 6281
Hmm, how about storing the boards in a set or map? That way you can secure to only have one instance for each.
Pseudocode:
public class Board {
private static final Set<Board> boards = new HashSet<>();
public static Board getInstance(String board) {
//search if board already exists on boards set, if it is, return that instance; else, add to list and return the newly created instance.
}
//override equals and hashCode appropriately
}
Upvotes: 2