Created
February 2, 2013 13:13
-
-
Save rirakkumya/4697304 to your computer and use it in GitHub Desktop.
型クラスを使って契約種別に従い計算を行うビジネスロジックを実装してみた
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
概要:入力されたCSVの契約種別コードに従って計算を行い、結果を出力する | |
仕様: | |
CSV入力パターン: [名前],[契約種別コード(A or B or C)],[基本料金],[使用量1段階],[使用量2段階] | |
※文字列はクォート無し | |
sample: "foo,A,3000,,","bar,B,1000,200,","foobar,C,1000,200,300" | |
契約種別コード別料金計算仕様: | |
A: 基本料金 | |
B: 基本料金 + 使用量1段階 * 0.1 | |
C: 基本料金 + 使用量1段階 * 0.02 + 使用量2段階 * 0.3 | |
出力パターン: | |
[名前]:[料金] (料金の小数部は切り捨て) | |
sample: "foo:3000" | |
※契約種別が対象外及び計算に失敗した場合等の異常が発生した場合は"error"を表示 | |
【入力データ】 | |
"foo,A,5000,," | |
"bar,B,980,1000," | |
"foobar,C,980,500,500" | |
"xxx,C,980,500,A,," | |
"yyy,D,980,500,500,,,,," | |
【出力結果】 | |
foo:5000 | |
bar:1080 | |
foobar:1490 | |
error | |
error | |
*/ | |
object PriceCalc { | |
trait 契約種別 | |
case class 料金A(basePrice: BigDecimal) extends 契約種別 | |
case class 料金B(basePrice: BigDecimal, packet: BigDecimal) extends 契約種別 | |
case class 料金C(basePrice: BigDecimal, packet1: BigDecimal, packet2: BigDecimal) extends 契約種別 | |
trait PriceCalc[A] { | |
def calc(x: A): Option[BigDecimal] | |
} | |
def priceCalc[A: PriceCalc](x: A) = implicitly[PriceCalc[A]].calc(x) | |
} | |
object PriceCalcOps { | |
import PriceCalc._ | |
implicit val priceA = new PriceCalc[料金A] { | |
def calc(x: 料金A) = Some(x.basePrice) | |
} | |
implicit val priceB = new PriceCalc[料金B] { | |
def calc(x: 料金B) = Some(x.basePrice + x.packet * 0.1) | |
} | |
implicit val priceC = new PriceCalc[料金C] { | |
def calc(x: 料金C) = Some(x.basePrice + x.packet1 * 0.02 + x.packet2 + 0.3) | |
} | |
} | |
object Convert { | |
import PriceCalc._ | |
import PriceCalcOps._ | |
import scala.util.control.Exception._ | |
sealed case class Price(name: String, price: BigDecimal) | |
private def spritCsv = (_: String).split(",").toList | |
implicit def str2bd = BigDecimal((_: String)) | |
private def contractMatcher = (x: List[String]) => | |
catching(classOf[NumberFormatException]) opt { | |
x match { | |
case List(n, "A", b) => priceCalc(料金A(b)) map (Price(n, _)) | |
case List(n, "B", b, p) => priceCalc(料金B(b, p)) map (Price(n, _)) | |
case List(n, "C", b, p1, p2) => priceCalc(料金C(b, p1, p2)) map (Price(n, _)) | |
case _ => None | |
} | |
} flatten | |
private def price2Str = (_: Option[Price]) map (x => f"${x.name}:${x.price}%.0f") getOrElse "error" | |
private def mkResult = price2Str compose contractMatcher compose spritCsv | |
def exec = (_: Seq[String]) map mkResult | |
} | |
object Execute extends App { | |
import Convert._ | |
val inputData = Seq( | |
"foo,A,5000,,", | |
"bar,B,980,1000,", | |
"foobar,C,980,500,500", | |
"xxx,C,980,500,A,,", | |
"yyy,D,980,500,500,,,,," | |
) | |
exec(inputData) foreach println | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
target version 2.10.0