Skip to content

Instantly share code, notes, and snippets.

@takawitter
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save takawitter/080804d8b84869c2269d to your computer and use it in GitHub Desktop.
Save takawitter/080804d8b84869c2269d to your computer and use it in GitHub Desktop.
書いてみた。executeメソッドのみ。元ネタ: http://bufferings.hatenablog.com/entry/2015/06/03/082323
public Result execute(Input in) throws IllegalArgumentException{
assertNotNull(in, "In must not be null.");
try{
Integer productId = in.getSelected();
assertNotNull(productId, "ProductId must not be null.");
assertInRange(productId, 1, 10, "ProductId must be in the range 1-10.");
Product product = dao.findById(productId);
assertNotNull(product, "Product doesn't exist.");
List<Integer> coins = in.getCoins();
assertNotNull(coins, "InputCoins must not be null.");
assertInRange(coins.size(), 1, 100, "The number of InputCoins must be in the range 1-100.");
List<Integer> supportedCoins = new ArrayList<Integer>();
List<Integer> unsupportedCoins = new ArrayList<Integer>();
filterUnsupportedCoins(coins, supportedCoins, unsupportedCoins);
int sum = sumUpCoins(supportedCoins);
int rest = sum - product.getPrice();
assertTrue(rest >= 0, "Not enough money.");
List<Integer> restCoins = new ArrayList<Integer>();
divideToCoins(rest, restCoins);
restCoins.addAll(unsupportedCoins);
return createSucceededResult(product, restCoins);
} catch(IllegalArgumentException | DaoException e){
LOG.error(e);
return createCanceledResult(coins);
}
}
// 最適化版
public Result execute2(Input in) throws IllegalArgumentException{
assertNotNull(in, "In must not be null.");
try{
Integer productId = in.getSelected();
assertNotNull(productId, "ProductId must not be null.");
assertInRange(productId, 1, 10, "ProductId must be in the range 1-10.");
Product product = dao.findById(productId);
assertNotNull(product, "Product doesn't exist.");
List<Integer> coins = in.getCoins();
assertNotNull(coins, "InputCoins must not be null.");
assertInRange(coins.size(), 1, 100, "The number of InputCoins must be in the range 1-100.");
List<Integer> changeCoins = new ArrayList<>();
final LongAdder sum = new LongAdder();
Collection<Integer> sumCalculator = new AbstractCollection<Integer>(){
@Override
public Iterator<Integer> iterator() {
return null;
}
@Override
public int size() {
return 0;
}
@Override
public boolean add(Integer e) {
sum.add(e);
return true;
}
};
filterUnsupportedCoins(coins, sumCalculator, changeCoins);
int rest = sum.intValue() - product.getPrice();
assertTrue(rest >= 0, "Not enough money.");
divideToCoins(rest, changeCoins);
return createSucceededResult(product, changeCoins);
} catch(IllegalArgumentException | DaoException e){
LOG.error(e);
return createCanceledResult(in.getCoins());
}
}
private static void assertNotNull(Object value, String message)
throws IllegalArgumentException{
if(value == null){
throw new IllegalArgumentException(message);
}
}
private static void assertTrue(boolean value, String message)
throws IllegalArgumentException{
if(!value){
throw new IllegalArgumentException(message);
}
}
private static void assertInRange(int value, int min, int max, String message)
throws IllegalArgumentException{
if(value < min || max < value){
throw new IllegalArgumentException(message);
}
}
private static Set<Integer> unsupportedCoins = new HashSet<Integer>(){{
add(1);
add(5);
}};
private static void filterUnsupportedCoins(
Collection<Integer> coins,
Collection<Integer> supported,
Collection<Integer> unsupported) {
for(Integer c : coins){
if(unsupportedCoins.contains(c)){
unsupported.add(c);
} else{
supported.add(c);
}
}
}
private static int sumUpCoins(Collection<Integer> coins) {
return coins.stream().mapToInt(Integer::intValue).sum();
}
private static int[] coinKinds = {500, 100, 50, 10};
private static void divideToCoins(int money, Collection<Integer> coins) {
for(int k : coinKinds){
while(money >= k){
coins.add(k);
}
}
if(money > 0){
throw new RuntimeException("Invalid coin combination: " + money);
}
}
private static Result createSucceededResult(Product product, List<Integer> change){
Result r = new Result();
r.setProduct(product);
r.setCoins(change);
return r;
}
private static Result createCanceledResult(List<Integer> coins){
Result r = new Result();
r.setProduct(null);
r.setCoins(coins);
return r;
}
@takawitter
Copy link
Author

方針的なもの

  • 非チェック例外も明示する.
  • メソッドの責務は他のメソッドに委譲しない.引数チェック内容はexecuteメソッド内に記述する.
  • コレクション内に種類の異なる値が入ったままにしない.対応できるコインとできないコインは明示的に分ける.
  • 戻り値の意味が複数ある場合(今回は成功と失敗(処理のキャンセル)),どちらを作成するのか明示的にわかるようにする.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment