Skip to content

Instantly share code, notes, and snippets.

@lagenorhynque
Last active April 30, 2022 12:49
Show Gist options
  • Save lagenorhynque/a44fe829267bd8504599688e2bc096bf to your computer and use it in GitHub Desktop.
Save lagenorhynque/a44fe829267bd8504599688e2bc096bf to your computer and use it in GitHub Desktop.
『良いコード/悪いコードで学ぶ設計入門』3章: Money.javaのClojure移植版
(ns chapter03.money
(:require [clojure.spec.alpha :as s])
(:import (java.util Currency)))
(s/def ::amount nat-int?)
(s/def ::currency #(instance? Currency %))
(s/def ::money (s/keys :req [::amount
::currency]))
(s/fdef add
:args (s/and (s/cat :this ::money
:other ::money)
#(= (-> % :this ::currency)
(-> % :other ::currency)))
:ret ::money)
(defn add [this other]
(update this ::amount + (::amount other)))
package chapter03_fundamentalofoop;
import java.util.Currency;
class Money {
final int amount;
final Currency currency;
Money(final int amount, final Currency currency) {
if (amount < 0) {
throw new IllegalArgumentException("金額が0以上でありません。");
}
if (currency == null) {
throw new NullPointerException("通貨を指定してください。");
}
this.amount = amount;
this.currency = currency;
}
Money add(final Money other) {
if (!currency.equals(other.currency)) {
throw new IllegalArgumentException("通貨単位が違います。");
}
final int added = amount + other.amount;
return new Money(added, currency);
}
}
(ns chapter03.money2
(:require [clojure.spec.alpha :as s])
(:import (java.util Currency)))
(s/def ::amount nat-int?)
(s/def ::currency #(instance? Currency %))
(s/def ::money (s/keys :req-un [::amount
::currency]))
(defrecord Money [amount currency])
(s/fdef ->Money
:args (s/cat :amount ::amount
:currency ::currency)
:ret ::money)
(s/fdef map->Money
:args (s/cat :map ::money)
:ret ::money)
(s/fdef add
:args (s/and (s/cat :this ::money
:other ::money)
#(= (-> % :this :currency)
(-> % :other :currency)))
:ret ::money)
(defn add [this other]
(update this :amount + (:amount other)))
user=> (require '[chapter03.money :as money]
'[clojure.spec.test.alpha :as st])
nil
user=> (st/instrument)
[chapter03.money/add]
user=> (import (java.util Currency Locale))
java.util.Locale
user=> (money/add #::money{:amount -1
#_=> :currency (Currency/getInstance Locale/JAPAN)}
#_=> #::money{:amount 200
#_=> :currency (Currency/getInstance Locale/JAPAN)})
Execution error - invalid arguments to chapter03.money/add at (REPL:1).
-1 - failed: nat-int? at: [:this :chapter03.money/amount] spec: :chapter03.money/amount
user=> (money/add #::money{:amount 1000
#_=> :currency nil}
#_=> #::money{:amount 200
#_=> :currency (Currency/getInstance Locale/JAPAN)})
Execution error - invalid arguments to chapter03.money/add at (REPL:1).
nil - failed: (instance? java.util.Currency %) at: [:this :chapter03.money/currency] spec: :chapter03.money/currency
user=> (money/add #::money{:amount 1000
#_=> :currency (Currency/getInstance Locale/JAPAN)}
#_=> #::money{:amount 200
#_=> :currency (Currency/getInstance Locale/FRANCE)})
Execution error - invalid arguments to chapter03.money/add at (REPL:1).
{:this #:chapter03.money{:amount 1000, :currency #object[java.util.Currency 0x3fbe503c "JPY"]}, :other #:chapter03.money{:amount 200, :currency #object[java.util.Currency 0x7b2bf745 "EUR"]}} - failed: (= (-> % :this :chapter03.money/currency) (-> % :other :chapter03.money/currency))
user=> (money/add #::money{:amount 1000
#_=> :currency (Currency/getInstance Locale/JAPAN)}
#_=> #::money{:amount 200
#_=> :currency (Currency/getInstance Locale/JAPAN)})
#:chapter03.money{:amount 1200, :currency #object[java.util.Currency 0x3fbe503c "JPY"]}
user=> (money/add #::money{:amount 1000
#_=> :currency (Currency/getInstance Locale/FRANCE)}
#_=> #::money{:amount 200
#_=> :currency (Currency/getInstance Locale/FRANCE)})
#:chapter03.money{:amount 1200, :currency #object[java.util.Currency 0x7b2bf745 "EUR"]}
user=> (require '[chapter03.money2 :as money2]
#_=> '[clojure.spec.test.alpha :as st])
nil
user=> (st/instrument)
[chapter03.money2/->Money chapter03.money2/add chapter03.money2/map->Money]
user=> (import (java.util Currency Locale))
java.util.Locale
user=> (money2/->Money -1 (Currency/getInstance Locale/JAPAN))
Execution error - invalid arguments to chapter03.money2/->Money at (REPL:1).
-1 - failed: nat-int? at: [:amount] spec: :chapter03.money2/amount
user=> (money2/->Money 1000 nil)
Execution error - invalid arguments to chapter03.money2/->Money at (REPL:1).
nil - failed: (instance? java.util.Currency %) at: [:currency] spec: :chapter03.money2/currency
user=> (money2/->Money 1000 (Currency/getInstance Locale/JAPAN))
#chapter03.money2.Money{:amount 1000, :currency #object[java.util.Currency 0x3fbe503c "JPY"]}
user=> (money2/map->Money {:amount -1
#_=> :currency (Currency/getInstance Locale/JAPAN)})
Execution error - invalid arguments to chapter03.money2/map->Money at (REPL:1).
-1 - failed: nat-int? at: [:map :amount] spec: :chapter03.money2/amount
user=> (money2/map->Money {:amount 1000
#_=> :currency nil})
Execution error - invalid arguments to chapter03.money2/map->Money at (REPL:1).
nil - failed: (instance? java.util.Currency %) at: [:map :currency] spec: :chapter03.money2/currency
user=> (money2/map->Money {:amount 1000
#_=> :currency (Currency/getInstance Locale/JAPAN)})
#chapter03.money2.Money{:amount 1000, :currency #object[java.util.Currency 0x3fbe503c "JPY"]}
user=> (money2/add (money2/->Money 1000 (Currency/getInstance Locale/JAPAN))
#_=> (money2/->Money 200 (Currency/getInstance Locale/FRANCE)))
Execution error - invalid arguments to chapter03.money2/add at (REPL:1).
{:this #chapter03.money2.Money{:amount 1000, :currency #object[java.util.Currency 0x3fbe503c "JPY"]}, :other #chapter03.money2.Money{:amount 200, :currency #object[java.util.Currency 0x7b2bf745 "EUR"]}} - failed: (= (-> % :this :currency) (-> % :other :currency))
user=> (money2/add (money2/->Money 1000 (Currency/getInstance Locale/JAPAN))
#_=> (money2/->Money 200 (Currency/getInstance Locale/JAPAN)))
#chapter03.money2.Money{:amount 1200, :currency #object[java.util.Currency 0x3fbe503c "JPY"]}
user=> (money2/add (money2/->Money 1000 (Currency/getInstance Locale/FRANCE))
#_=> (money2/->Money 200 (Currency/getInstance Locale/FRANCE)))
#chapter03.money2.Money{:amount 1200, :currency #object[java.util.Currency 0x7b2bf745 "EUR"]}
user=> (money2/add {:amount -1
#_=> :currency (Currency/getInstance Locale/JAPAN)}
#_=> {:amount 200
#_=> :currency (Currency/getInstance Locale/JAPAN)})
Execution error - invalid arguments to chapter03.money2/add at (REPL:1).
-1 - failed: nat-int? at: [:this :amount] spec: :chapter03.money2/amount
user=> (money2/add {:amount 1000
#_=> :currency nil}
#_=> {:amount 200
#_=> :currency (Currency/getInstance Locale/JAPAN)})
Execution error - invalid arguments to chapter03.money2/add at (REPL:1).
nil - failed: (instance? java.util.Currency %) at: [:this :currency] spec: :chapter03.money2/currency
user=> (money2/add {:amount 1000
#_=> :currency (Currency/getInstance Locale/JAPAN)}
#_=> {:amount 200
#_=> :currency (Currency/getInstance Locale/FRANCE)})
Execution error - invalid arguments to chapter03.money2/add at (REPL:1).
{:this {:amount 1000, :currency #object[java.util.Currency 0x3fbe503c "JPY"]}, :other {:amount 200, :currency #object[java.util.Currency 0x7b2bf745 "EUR"]}} - failed: (= (-> % :this :currency) (-> % :other :currency))
user=> (money2/add {:amount 1000
#_=> :currency (Currency/getInstance Locale/JAPAN)}
#_=> {:amount 200
#_=> :currency (Currency/getInstance Locale/JAPAN)})
{:amount 1200, :currency #object[java.util.Currency 0x3fbe503c "JPY"]}
user=> (money2/add {:amount 1000
#_=> :currency (Currency/getInstance Locale/FRANCE)}
#_=> {:amount 200
#_=> :currency (Currency/getInstance Locale/FRANCE)})
{:amount 1200, :currency #object[java.util.Currency 0x7b2bf745 "EUR"]}
@lagenorhynque
Copy link
Author

📝 『良いコード/悪いコードで学ぶ設計入門』サポートページのサンプルコード

  • codes/src/chapter03_fundamentalofoop/Money.java

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