95%B+mVtS0T
z;+353hb9Zj8ES6w&lM*vkyMEu7GV1?SH6Lbe+t^HB`pXJu!D<)~w%jnc-5K_7%
zO6U%$5-%HKuAxU-uUJccJGdlUo%^j4q&=n|p~Rw;w#;{rzCZUU^Lf23QlS1IeOjX}
zMu5y^G1swKBQi}wZlOY}zUGi?)~U#q{B0E4!!3lz3|X$McxC+g$BbzWTFB}8={raS
zOcQZyy7JPu;io>;cS;>P-aCKkxUEI-C&%>tj+vmke^?x^EoD4<&eHR215q>6NuN0*
zgO0uIb{0hW`wGMZl0TyBrEoaY+}N`!bGIB5ekA1h+gRkDEKgGnb$6{t&N;hJg!l7#
zKOWuvw0a9+y)`U5J%F`>Sw4#WNbxzII^$9_#;bqq$a_Mv@pV+u3(s#aIb-*qw`qJ1
zEBEl;ffgKh@H$Jb%jbr7K9%k3z+uk+_G&9R<`=Y(dGC6r&knIF%{yu9!)Lju>oh}G
z^34e?>a3pRH=31~zOv|#Q(N1f4vw#kjgQ(^R1?oQIubbe=@*S=+#N&D?LcE+Fw5P
z*_jk}&c+NM8Y^yoZEJS6Qr?@d+tEi`R~nSZtBQSHgEIr8Ed8fHU0fR8m_8u;*hXo(
zxE(dO(_YD0PsWL^WA-RrAS`04)mei+nSph5_&f9N%nZh?aZ&JGEeWKXqf9>cIMDwNR#dcM~pldGz^i!7i-oN
zN6Idftu_hfA0jwY$_yBXRg>W+sMA#jx#@+m2H(@eZ9?Gao{M`>m!I#JL|+2e^|e3b
z;gpC8Y!8bQHmu*}c)Es~EjWd;iJ!f$@G0oP=wh(}Uq-$@?=L2{RI
z@$hi3s4g{hI%UDAI1n4xs$gc*^IWw5HG81WDn0hQ*+}m4dA^b>+no{RHLUdvFWw-Y
znEU|*r}ApOP!3qb6_Z72N8M1&JUMi);=`$6(d1{d9Ct_>dhB<+8*&2_1*MRnQ$|6SQBF&r8RXX?w}AM3dtUCL(Xs4B$^2PZ99k
zV5(Yh4wL$mJZXD13Ns}N7EJ3&4l%mq41B4NFml6V4tb@V^ge4@nYnMTw{|Z&p2XSQ
zh?PLtac;603ZYtt9Kq8FHF{R=^t|f6uZPuF+P8GipIV8ta;Ftos=APL_eHq7J168W9;>sT8I1mU6Oe$+cO$Oq}L`p
z=m{qodiVs{*^5r7*N^Sq$c9FT?cQnJ(6zfHkAjx1X&=h2_;?mpOJJneMPc`}?vhq)
zEUOD?$cqznbm$cekyK3v^@alJg>iL&+w2+3Jk^~$1Vs)HoKdyg;qmP>;Y$!to75bq
zz|7sYX^i3m?=R7_
zHjailF^ZluL^v#aZDK}p|g5mIIegG5pV7L`*2Oz
z?T&r)$$Q8RMW+etkFpEabtVsxjRH9CcRXZ{^e_l7uQwCINq|}M_Xz**J<)dwK|Tm6
z4Biv4IzC=C6=4q0i!X03=h}yPAFt@1IYP@%LD31>C|X`p7p5DnA1SQb1S;RbKE6i>
z);#Nt5yirKVc$47njW`R?fVOHtEx^tP-l-4CTK3GmGbrd$*Trfr=Zvd%xvG1
zMmgooMmb+13Eth=yPsDy$>VXC-&`;Ag%vsT8*ep-eBVtQ8M~%k#n;|$Uc7vBIQ2mj
zC`qj=q$b1HOzYG=%s#VHXG_4#48_%p1oR}I(R_)aS$cIb43(L(i^_guVKM{==Q!PR#kL@e8m250(5TH_Zc^ULGF
znf^)ef=hkUCV(>mX7sN(3|$J*6GZ&B_Vy!@p)fKy6O;x2bJO7c{8!$zm<9p0cLm~K
z4b|q~tSH+z@0mNCZC>t{5f4XW&8uz}`Wo-s_V0nS+Kyua{!E@52A9PnN{QBvQHS-L
zK=O=j7)LfdK9mV~*uf4{YtQ^+zy4%^!DVNd-86`U9)#d+Z7e`maXdmwaY9}_WNl-O
z;%mCGl6be4uO_)>7nrPyYR9f3+gb0J)+_GspBx0g}eq+MagV
zJ-mE|ih#noeypTr6G%9AE~PgoIf
zHEcAar@VOC5)jpeb_3z^@U7}g1%Unb)x%qqG&L)aJ9&9s>R}c&O3qG9EBFX~EvyTN
z*?*&sxsHWC4uj0NQ0J8cAOWtsT}tJr;OibQ&LA#Jq2MP({%+0yYg
z>r1RPcCOF2<<|F)4+g=jD6J=P11fql+1FT{Xcsl
z4g{c3wK$c3i5Ub%mdplD9@(s9ABPboKPiY8P0c{+=20XcB3!CVyq9Na%=(bL>)-IV
zDIYG%xGdc2b}A0<4KH#asIr!(Fs1Jg{#F;Z+s1-`e8kwh|7Xvunb5q~ydzw`4{1-a
zBVlc!LSkWh#HeBnd{$5??+>ogaaS^!I5AM)9Vs`EITZEF`Kwd0wM%cuc(Q5N6X573
zbZM`hi>Vx)Ug~14)YYIXRjo<*vSn=$&i{>!d9j|evp*OUr~>Yebca(I3Gcej3vT_K;_o7VqFME|KXE{DA5Ei$+8zbM@03p*Jr!z
zMHY9-_j*M2T3$@iZ7Bf-MCYxQ`Jvf^qHJR6%>kvrjOK&!c6%>{{3QN|Y(qPyeeJ&n
ziaw6D;XYJ?eqQK5A^h)D|6dB>|5qkUT^zbOQE|*T=tWPtdoc0E+N5qs&OB9J(+_Gw
zyg+EO&X{eXWC*0w?Le-0Ks~xOQ1Kl%8uY
z0~=y&SOd5Clam8v?3-o#K}7Q@)Qda*Qo9Mrcm?l03ndqpS6Wyr$u!PYHKL&2cC>#G
z{F1}Fhx;;3@D_uBDD=$N_;oG3IF`EJ4~Ru*!icq%`^4HR^4S}pK%xr{H3AKBwC~rA
zI%{A=LEiJ`qC;H8=zsmv%oNC~t|eD&h!O^?Zi`)fF*G*JLlU4iogd+J^=o^!jRP$Y
zt?u0VbbWqx(6)cpk?>rJ>Y8RHhBypx4QOyM=Da#6DBU4REgVjNw`Gq)YwqRpwra7>
zL2Ih}tLTwAZ=jcUzN~^!-O4`KWid#lVC$wQ_q<*EH0QG+@mjkZsDEb6Nl@0BEbe*>
zg5*Dt)A{WF5cr!rYc7>~kzMQk6IdV9f=bKASTmgdIAy_);r({U5N<+?y!{83*M$9j
z0GdufWdbT-w*2jme%##epcE*toqhG^3WI|X1&YQPsY1|)mXS_lz<-!g#%JAmlSK{nY*
z=6J#`WzQdFSIhu+9Qg%DIz?Fjg*}!3ycbPa$Ze!M043h+QH|aY6~W+T-QT~LzDE;w
zo?YRd&S1v|01Z-q3xae0=hXk_y%2<&_~o+Js;Oq>L40Z731EGYjS@8^GG4j)ugu#|
z&33zVFFr}@ANlt2HEF|El`DM#EWgE?%O08ufyfQ-*(mGJsRW|SE}*w(BTDo9SnYFU
zfc_}J+v8p@o^>P{@E7!&N1y)!+ORkL0@Q3g_JS5
zvwLcx;<(yprm5iS>rsa8cs&;72w0RZm)hl~key=ZN+kq;HoXyQN9e>pA4eJY!6t{;
zIZ*yXSU)3DR4?vIAR4O5!73dD6i{g_3-CRe#yKW~(-cFgUU=%T(UN}riMQ3ykNotMy+VWqHw2qV8>HMY~u5z}tk0VZIfx7Vnjp
z2J5}J;c!A6;91H|cXE&i0qHl%&O?915doZph`$&e*t66qI4v$1dTOYpv~>50>p_rR
zqiK_9;+050ig<#5r03W6LK#;{)xp687X!kVb$`-)e}}QjkELwDB=z<^uc69ShmPmA
z0oDsvGkf~41ad=}=SpN?w?huT3GkMd%oW^2ig-`@*{GhJ&4E9Q2{BvG5=ikfSsw8b
zrzl&xT2oIm>#Kd|;5tH{PgFZ~PP*G)hJe^-CTA_>^bM`qt
z{b(gHfa}lkuN@O<4d2PG*`e6`S(Q%cIO+14{!8PI{8
z^!9CN9vrt^FftVIMXN}hKXR4B4l+L{ghc*kh_p@;6ocUH2XPYM4p%cdKa$?Fvp?>8
zRpraK9-1}hqkvV3O+fs`LH*}Jel{Xi^MeVR2xCpy+LvD&2kIqN^_A}fK84}{i%X7u
zDU<|ad(}u=M(CoW)E*r7g}whAdI4R6-^5!1D0$455NgCBLtXx%xyfCzz_geE=z;F#
z5&<5v$?56)Qy^3)h~<^Nf~fOBK*74ZJPtmj8xt4ID@xDTak(UN>)RdQC=K=%@YN8x
zDPU}rj`Rf~s0nhPK?FXO6e~?lKLZ#F2h@zGlq8rsfEBbBClkRshIsucilI7Qpb=ca
z5!2^wKLxyxxo(!Zp?zGT5y+hNKBqfD64W243n#7T+;aufWh+2=dTN6^xJrfm3=uHb
z?o@Moyr+lX{Fhie$T|f%Dt9Y+JR9k)EdBfbKvswgR18
z?*jfzrVlboA703i<<8Vl`1m_-6QE@nR+qta1~h1`84m5|-g)&wJg_{xP?>ncJ7x^5
z!4futx2J(YEAMm7!dEfh_`8h9x{}f*AOjE&-5l#Fhxo62IPz@Yv+4Z4Tu*DVS|yZf
zA=0N>&jntQ()TV(-W`9*9(aGpW6u-h9H~v(-Qe+^0MBn;VKCT|;=(U^*=)fqGX56#
z)F4TwF;+^-()7o=aWqsfju2ADDtUg51E#FF+GVCoN1l`hffOhGnxmV|m2Pb@)C9y(5kS{0`@??j_GqLb@=3>*W`h(jh>n1T;4bwLYpA?l`4
z`xjNZ?6(}#{ABO1*;&uISA+wWCfdePods7jEh{mYr1WZDsEYHQ2c?A*kLvV!N{ydy
zWdx-{t?PTnsX0(VI1AtUc1q^@yKU~E2I+1rf!P5?bCe?oKw9hrVV`$ad5a^n7NTGE
z+}Qp+m6ktC3@}q~pnNL^eqR4u4
zSbm|swV7JQ7ec~5hbsijld8gjo0R9|)E@L^UG()fT5epM_8}qnN9UiS3*YkFfr4^Y
z&I8a^-5^mr^qL^TOZ?l$P44)B0MNa7v{^PVs~-=S9U)?aDGab!4GHO_#L#e?H;)tT--6nf95p|HW5oRR#p@PsxaaLE7
z$mXdtM1Cs(^>KGWt2j+@DAB0G8C2iW0+(;xSq{iC!Jpe8BqV_Ak|z(fEz2EB-X)8C
znDmlzMH`V9g*4jxm1HgBhQ(9H&H+`6DCKYu%h4eC0isqj>fdib-=Wb)lckTC%RWTJ
zY6Wgc(Q^5ggCH=l{>_5oCe@ck@*8peGZo@K?la~VK!rme^)fHlk_llHA=l+;v1l(W
z)nWH;x_K837kPq#IK!_Rq4uCA>v?P}Le{r9GXp>dTd65?3zG7oJzpMVbym1Zf^!85C2$#i(+4a9=B9X$a)T|=w}jC>N`M*FjZD&E
z$5C}0UZKYvZr2?GRP#7ukmHqaAaod4UJj75VJ**<+COQ(G66JZG0Uv=_w3pUhs+*f
zNOH6%d6Z4RJw{Tls3{)SjEr_dQ^OMNh8|mrYi)pWhk2NHAdTWi^e=
zrHw60
zKDWcPBBAt-Fk&Lc{;xOVp>4&~uKjo)M)yps!wE7*mNjf{hVOpp0;Z!!K~;nf#r!}{
z%}5V`g&0OH$3EBrdBciqbgFWRCoumzS&
zFGw#thy3;|+)(LsKF8s+iAU)W5xoeMgHsJDd~qt?Mb&tWHFa<1*TuMqSev*lWU!#$4f@n=@-Y`Ad8dgl$#{e3+*ZBR!eRPN07^6#?OhC>I0?R?MeN_9E
zQ&$htg)WFVp2roRb8vK@99rkmq_x8a*L$d>F%oII-!flDgfn
zrxHB15Jhs|$zxcbj}EbV8#9K-4~{ste=uC1Eim0#Xro)&(jC8TCpuBJ=(~dNXFBDB
zaZ3R6y{Q~^$L548odmnIl6_|oYD?l$GC}k%ro<3=YZBn)e79N4&s?B3Bj6}6G(|VJn(&~%;LnMQlO<1D
zJReI=6EN;D@?q?P3x)1mSdslemJEZ6LDdhksd#aa#!D4JF@WB3I5M^Ogxm}A)3f#2
zBco{Co$%%!Op|ndr;K?;Db3l*TLS_G2w$IG$AM-S(jNYObWH|7X_hfs7IK8yXF2n`
zKK35Pl?bv-dhd&jYJR8>#QaOOPCe^ur!1a}SE}YauJ@HVoqHGFs~~ay2Z$#|06u?Wb?sxE7W`hXby1-{!Tj1Uft<7^35eUqMxENZ813Hwzg7HY8aU&k#_tBmEV3P7wB;wDhU<(S>2rNz>KLa5W~w_jeE
zq2-L5Rz8q2FM6}wp%eUr9Ph7(8lv7a#Hd;WSHlx}8f`4Ga*lSGem}1{nw0`WpCExC
zHq~Soz9~musaVaE2!T>2Ki(`B>aB^_;vVZ|T(fN35(h-%$wM(nN?1wF*13|MQ#jWs
zU+{2Z`Bm5E%ET(bo!`c4KxU2e+4r~v=v`U6F!x?Q2fRq|Q92;v2LO*ToXD>{R+i@L
z`tc9v9boHc0Ho_eE&|cGH)q>=wm`%866R8MieRkuA9DQvE46_Ce%+?cpy-O
z$bmrys40IUu|TI$W)h;f36ML{c7E~;{3+C>1~j3tHncr(2-M6E
z!hEZTi9ly8Vl^kLcHaV6C`Yre%6qD*J==%`RLmU96+nA-_FwI&hdOBHA=e&|CYykd
z<0{k+2YNf5@+kvfCu)H!u#Is#7FAsdcnRNHu-dR--NXnR(iqZ|Tco^AtLf4oqL%=(
zhF0O}IQQuldC^@M#{`|2d6@a{69Y`A1l+k&Md0CV0>IcF3Lk;s%bF8VwD4P)mIjn*
zJ|uTa%|akMNr<^DMDrP%wqKsKCKJS
zfOxt%9$S;2yB#74kFc#^Y$iNp7h2GX!Jv+wacV4c9dObFoUvatBZL4oNy-VMReh$9
zL(O01pwDp>>S~H7qPwx`tofE%_*{>BWVl%PA%1bQD?Eyyx50GPSxd#sLLQ*culerL
z2x5<$t~;;`cJD5fAa=fDyDSGsf!m^B`?Jo)0TC7wvPG)T0a9IWs5yz*qVcf|^u~72
z4FIbnjiaZ?wsBPasg=OO9&90Hs1MAT(Xf=eXU2O&^hm=;_vnNR+SZPN;6&~-bTv2n
zAw$fmYbMC!xFMy^QXdFAG^;H-Ee4R@_W~9UkTZU=#hF81ka@|P
zwLok0+ASU^{QwIMXY9UBDEEtwcrv
z3a@jR9IPFo^z}$3m#s#n2Sh<(EVH_bAz8vIPg)1q1DYQ0JKgl|(E+AY946}taE3Lt
z;}Nv6x@TSaP?Jw%NniUAc`OQhM;E6r;~#SR!V(H2<@$1?KxfdU-yHbI9_a`lwam&t
zJ0R>=P46hmG`w^gBDkNjy^QzI0g_$JjeuI_hcyfD2GNB{FDb4sG|uRJW}Fi<4+eYG
zDf$<^N}*(6m4z2U6b?*(f$q7d8|n%6)!0F5KKe|qGRLNakdv`rxAL|Fhk?CMyUj3W
zvsQ0D@KFr{&Wu>>es<5X&2kBFpg2qcp0ab`qk+Q5U!flEt^w-w+-J>Vudx&k1>jd3
zr6nhRPY2xpKUXAMyLi>A@DUK1GC-xw!<18Ppl)E)(o-3=ha`t+3Dr#Hc~Zf~znb}IR?fSTuG
zKd3p8)_Vvvs>E4aS7IJ`u(p*+8g-7eusi$zErTOS6eYtJQz4rePV8Gsp{o*aX0u8>
z=TCJiY}P<8XcD)?a_68dI2neUhRc+eH{DVBsbc;m(5_UL`i@ITH#TeN*S{8lxpu;A
zht4f1Jh!B0;#-0uS7P|cF(Rw=_}W~Ye!w;pPD?-~CLJo$;v_R%ct*x0%V~vt0p1LJ
z>8OatVfy49;vOo(^@EthFM59{`W;S}OwNqxk>$
z)Yf`rDzI(OUDNyo*1=)=^Zlz7WRUR^fb@a}T0=?yR^3~T2O?FVMEiM#&h^(;7JrTd
z>g1l&1bv{O5{@gI*M5V%-@E0khOjc>Z+YJ{&V1;Em=@f{~vojj*v6CL+$Xt4=*4>
zh7b4G-12c=ectu{Ro5GKz|c?yDG~q}`9UCUZ-KAVSz6$$WqysmBihk^~9T5
zLTdu@mm?f?jpPA_(h@4gC7cP*F*o~&yQIal&_NBtxK
zk~-3Pz{T-L!^CubCJa=joF*XohWe8m&M09Ti8F2e@(g
zV}F*)|5o7t@Q?jlv;V^`w7NlKbv*w^FTf8u{fEP4HLvoIP`{cR<6fOeej@V!Fr@v&
z7Vx7;`_E&n$*%vCqv6Pl7BrIrx_$L7o`2=
zQ|B4htgma%|CSF8JYdow5}trmc&L6d>FO817NN)i?
zeAe$Pv>QMZr2pIZgp8HqB!WvIQQM-#fvvYU6R(nf+|VvyQtJY{dg#JZ2$BgvNU)T5
zNRkJJ9N%)BL9r|7;5%B)Ia~zoHob-rF({VpE3E3%`7)Sz%yFF?unN*?2^@P7
z&gB^pVE}En<3vCTh;S#%y=%XHy)FIh*lU5uI6Ro8n8AX}xhTl9$ZQz|K9b`4tb$yB
zGRL}mwH!WUo{XZfJ&J8SLBYhOV-5rqQP(vi-%+q^*Hy9_YlwfVRKQ_CO(W`Gw!21MD^a$t*LGG&$L82PnW$k_pPx6De*
zZUDBxtS>8bhJT|rek(n4=ABo&?GrC7dM#DGaQYzsJ
zd>?=3b__-4><%GE!
zq5f{fBMOH!dEBVb3lKI~Xzwo2<%pl&1^Oy2M+Q#wD85Pbo9)VAOose(cIpR)y$s}x
zRrCK8EIRtaf(0-n;tsFiK{2|=mO7}U2;i9nJ`&BHXe^2{VG0Z$guuemB*kHPqZ8gOh+MkssK-680J1w>XjH)rU&cXUH*eaeH28a+}i8RrW2(vo=}@)WAvb
zAl;T3QR<7SW|XiZgEP2rGYjjgZ?Cv!mHcvBvMitPMAhy@Td#Qz
z*Gt3>7vNoSF6sV(&|5`cTlPL2%%`g+?TY&c3q9kX?;1fY59?9(n*c1Eb7?FhLjDh($?5JITbkx
zJXJI_9~|62Ip&OApGOlyPbLh-b`y48@IX<)wsVrjqQY%Th6JA0;OJ!k1(dRH=0FG7
zAId(Tl55dXdp3KB7~xIPOX{-+4m6uewT?{*1Zl^nIO*9p2NqNslx%@OfJusvQ}e4>
zR>94Tf_^mzL$k;B|F~g3G+=PDAm^=bhYwnx9CN-3wRg5jrsc`XeW4$gX*t7UOC{r4
zOu(f?WXve&q`TolvKVSx4lsQQ=nf1Q-In~G*D?XahLhzQ(ycETDU-uV0CDlhjtx-o=gzU{M!v>E^)hj(_3YV@
z72h+Uiv80?{6AS^r64I25{1G!kJ(*P{{Y-jsnz`zr_V@s9jNP4kAApx$}*R|`@?mg
z_ZqC8NPv~2=p{tdwn_Q{d+`%s{qrj6B5H>V#_yJ~EAx8o(3Gf1$$JpupJ>7lvaayk
zu}6UER+K?+U*(;Lh5_NGm*C$5*+Qm3+B69*1$9Yxxq!(7-bddDG!Oo(2#;3wO&_*-
z+YLFvAf_5hRt~g*(w~n9FrDwfdi#P|2sK+OFl$ABR``W>V{sCNPF-MwkhRRvk4Zq1
zr+@fCzOQZ-`9BjyfFAUXT>NEFqq>0PLHaL1_y<)Ys9HRwv=8?A%~`GnNLk2kh!_U)
zA-XP7q-96f2_VN(fL|LYu@{&|K^C7$UtG8rYy%~KeXwmvueI-Ax+B1GH)lcf0ehza
z;1CgiB(YE}eB;IXK~NET2F#d&SP870`n6M*z(pEO6VTnGJ2%!#I+~UEX*G4jW-oz3
zl>;oNKX>(bhGH{ttM>W$U;T+eD>C69d$FG0fd+}&BmbA%dQHiy3D8!mj=dEnV6#@f
zXT^6l5n$&y66nK5gO1?FSFbMGl4Bl$`hyoO%!dXwzI>$05TBT-iI=`Q6U|WEA+>^48i;GK_Ka{Gzyf`Nh45?mVk6C1X5Lm4E
zNtx?cuWqV+R@{zIGl7Bqe8HBvSRnXc6
literal 0
HcmV?d00001
diff --git a/src/main/java/subway/application/domain/Distance.java b/src/main/java/subway/application/core/domain/Distance.java
similarity index 86%
rename from src/main/java/subway/application/domain/Distance.java
rename to src/main/java/subway/application/core/domain/Distance.java
index 88851ca90..4428cc688 100644
--- a/src/main/java/subway/application/domain/Distance.java
+++ b/src/main/java/subway/application/core/domain/Distance.java
@@ -1,6 +1,6 @@
-package subway.application.domain;
+package subway.application.core.domain;
-import subway.application.exception.DistanceExceedException;
+import subway.application.core.exception.DistanceNotPositiveException;
import java.util.Objects;
@@ -15,7 +15,7 @@ public Distance(int distance) {
private void validate(int distance) {
if (distance <= 0) {
- throw new DistanceExceedException();
+ throw new DistanceNotPositiveException();
}
}
diff --git a/src/main/java/subway/application/core/domain/Fare.java b/src/main/java/subway/application/core/domain/Fare.java
new file mode 100644
index 000000000..57a6e630b
--- /dev/null
+++ b/src/main/java/subway/application/core/domain/Fare.java
@@ -0,0 +1,60 @@
+package subway.application.core.domain;
+
+import subway.application.core.exception.FareCantCalculatedException;
+
+import java.util.Arrays;
+
+public enum Fare {
+
+ UNDER_TEN_KM(0.0, 10.0) {
+ @Override
+ int calculateFare(double distance) {
+ return BASE_FARE;
+ }
+ },
+ BETWEEN_TEN_AND_FIFTY(10.0, 50.0) {
+ @Override
+ int calculateFare(double distance) {
+ distance -= 10;
+ return BASE_FARE + calculateOverFareForEveryDistance(distance, REFERENCE_DISTANCE_UNDER_FIFTY);
+ }
+ },
+ OVER_FIFTY(50.0, Integer.MAX_VALUE) {
+ @Override
+ int calculateFare(double distance) {
+ distance -= 50;
+ return BASE_FARE + calculateOverFareForEveryDistance(40, REFERENCE_DISTANCE_UNDER_FIFTY) +
+ calculateOverFareForEveryDistance(distance, REFERENCE_DISTANCE_OVER_FIFTY);
+ }
+ };
+
+ private static final int BASE_FARE = 1_250;
+ private static final double REFERENCE_DISTANCE_UNDER_FIFTY = 5.0;
+ private static final double REFERENCE_DISTANCE_OVER_FIFTY = 8.0;
+
+ protected final double startPoint;
+ protected final double endPoint;
+
+ Fare(double startPoint, double endPoint) {
+ this.startPoint = startPoint;
+ this.endPoint = endPoint;
+ }
+
+ public static int of(double distance) {
+ return Arrays.stream(values())
+ .filter(fareEnum -> fareEnum.matches(distance))
+ .findAny()
+ .orElseThrow(FareCantCalculatedException::new)
+ .calculateFare(distance);
+ }
+
+ abstract int calculateFare(double distance);
+
+ protected int calculateOverFareForEveryDistance(double distance, double referenceDistance) {
+ return (int) ((Math.ceil(((int) distance - 1) / (int) referenceDistance) + 1) * 100);
+ }
+
+ protected boolean matches(double distance) {
+ return Double.compare(startPoint, distance) <= 0 && Double.compare(distance, endPoint) <= 0;
+ }
+}
diff --git a/src/main/java/subway/application/domain/Line.java b/src/main/java/subway/application/core/domain/Line.java
similarity index 92%
rename from src/main/java/subway/application/domain/Line.java
rename to src/main/java/subway/application/core/domain/Line.java
index aaf0a8a1c..49087ea87 100644
--- a/src/main/java/subway/application/domain/Line.java
+++ b/src/main/java/subway/application/core/domain/Line.java
@@ -1,9 +1,9 @@
-package subway.application.domain;
+package subway.application.core.domain;
-import subway.application.exception.StationAlreadyExistsException;
-import subway.application.exception.StationConnectException;
-import subway.application.exception.StationNotExistsException;
-import subway.application.exception.StationTooFarException;
+import subway.application.core.exception.StationAlreadyExistsException;
+import subway.application.core.exception.StationNotExistsException;
+import subway.application.core.exception.StationTooFarException;
+import subway.application.core.exception.StationConnectException;
import java.util.List;
import java.util.Objects;
diff --git a/src/main/java/subway/application/domain/LineProperty.java b/src/main/java/subway/application/core/domain/LineProperty.java
similarity index 95%
rename from src/main/java/subway/application/domain/LineProperty.java
rename to src/main/java/subway/application/core/domain/LineProperty.java
index cce9e4420..8f9f6c8d1 100644
--- a/src/main/java/subway/application/domain/LineProperty.java
+++ b/src/main/java/subway/application/core/domain/LineProperty.java
@@ -1,4 +1,4 @@
-package subway.application.domain;
+package subway.application.core.domain;
import java.util.Objects;
diff --git a/src/main/java/subway/application/core/domain/RouteMap.java b/src/main/java/subway/application/core/domain/RouteMap.java
new file mode 100644
index 000000000..90c151927
--- /dev/null
+++ b/src/main/java/subway/application/core/domain/RouteMap.java
@@ -0,0 +1,102 @@
+package subway.application.core.domain;
+
+import subway.application.core.exception.CircularRouteException;
+import subway.application.core.exception.RouteNotConnectedException;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class RouteMap {
+
+ private final List routeMap;
+
+ public RouteMap(List sections) {
+ this.routeMap = alignedRouteOf(sections);
+ }
+
+ private List alignedRouteOf(List sections) {
+ if (sections.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return alignSections(sections);
+ }
+
+ private List alignSections(List sections) {
+ List temporarySections = new ArrayList<>();
+ Section indexSection = findFirstSection(sections);
+ while (canMove(sections, indexSection) && !isInnerCircle(sections, temporarySections)) {
+ temporarySections.add(indexSection);
+ indexSection = findNext(sections, indexSection);
+ }
+ temporarySections.add(indexSection);
+ validate(sections, temporarySections);
+ return temporarySections;
+ }
+
+ private Section findFirstSection(List sections) {
+ Station firstStation = getEndPoints(sections).stream()
+ .findAny()
+ .orElseThrow(CircularRouteException::new);
+
+ return sections.stream()
+ .filter(section -> section.hasUpBound(firstStation))
+ .findAny()
+ .orElseThrow();
+ }
+
+ private List getEndPoints(List sections) {
+ List allUpBounds = sections.stream()
+ .map(Section::getUpBound)
+ .collect(Collectors.toList());
+
+ List allDownBounds = sections.stream()
+ .map(Section::getDownBound)
+ .collect(Collectors.toList());
+
+ allUpBounds.removeAll(allDownBounds);
+ return allUpBounds;
+ }
+
+ private boolean canMove(List sections, Section targetSection) {
+ return sections.stream()
+ .anyMatch(section -> section.getUpBound().equals(targetSection.getDownBound()));
+ }
+
+ private boolean isInnerCircle(List originalSections, List temporarySections) {
+ return originalSections.size() < temporarySections.size();
+ }
+
+ private Section findNext(List sections, Section targetSection) {
+ return sections.stream()
+ .filter(section -> section.getUpBound().equals(targetSection.getDownBound()))
+ .findAny()
+ .orElseThrow();
+ }
+
+ private void validate(List originalSections, List temporarySections) {
+ if (originalSections.size() < temporarySections.size()) {
+ throw new CircularRouteException();
+ }
+ if (temporarySections.size() < originalSections.size()) {
+ throw new RouteNotConnectedException();
+ }
+ }
+
+ public List stations() {
+ Set alignedStations = new HashSet<>();
+ routeMap.forEach(section -> {
+ alignedStations.add(section.getUpBound());
+ alignedStations.add(section.getDownBound());
+ });
+ return alignedStations.stream()
+ .collect(Collectors.toUnmodifiableList());
+ }
+
+ public List values() {
+ return Collections.unmodifiableList(routeMap);
+ }
+}
diff --git a/src/main/java/subway/application/domain/Section.java b/src/main/java/subway/application/core/domain/Section.java
similarity index 96%
rename from src/main/java/subway/application/domain/Section.java
rename to src/main/java/subway/application/core/domain/Section.java
index 319941ab6..c8637856c 100644
--- a/src/main/java/subway/application/domain/Section.java
+++ b/src/main/java/subway/application/core/domain/Section.java
@@ -1,6 +1,6 @@
-package subway.application.domain;
+package subway.application.core.domain;
-import subway.application.exception.SectionConnectException;
+import subway.application.core.exception.SectionConnectException;
import java.util.Objects;
diff --git a/src/main/java/subway/application/domain/Station.java b/src/main/java/subway/application/core/domain/Station.java
similarity index 77%
rename from src/main/java/subway/application/domain/Station.java
rename to src/main/java/subway/application/core/domain/Station.java
index 1063c3993..a0790e9d8 100644
--- a/src/main/java/subway/application/domain/Station.java
+++ b/src/main/java/subway/application/core/domain/Station.java
@@ -1,4 +1,4 @@
-package subway.application.domain;
+package subway.application.core.domain;
import java.util.Objects;
@@ -25,11 +25,11 @@ public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Station station = (Station) o;
- return Objects.equals(name, station.name);
+ return Objects.equals(id, station.id) && Objects.equals(name, station.name);
}
@Override
public int hashCode() {
- return Objects.hash(name);
+ return Objects.hash(id, name);
}
}
diff --git a/src/main/java/subway/application/exception/CircularRouteException.java b/src/main/java/subway/application/core/exception/CircularRouteException.java
similarity index 84%
rename from src/main/java/subway/application/exception/CircularRouteException.java
rename to src/main/java/subway/application/core/exception/CircularRouteException.java
index 7a9dffa7e..f6d6649e8 100644
--- a/src/main/java/subway/application/exception/CircularRouteException.java
+++ b/src/main/java/subway/application/core/exception/CircularRouteException.java
@@ -1,4 +1,4 @@
-package subway.application.exception;
+package subway.application.core.exception;
public class CircularRouteException extends ExpectedException {
diff --git a/src/main/java/subway/application/core/exception/DistanceNotPositiveException.java b/src/main/java/subway/application/core/exception/DistanceNotPositiveException.java
new file mode 100644
index 000000000..2179d1484
--- /dev/null
+++ b/src/main/java/subway/application/core/exception/DistanceNotPositiveException.java
@@ -0,0 +1,10 @@
+package subway.application.core.exception;
+
+public class DistanceNotPositiveException extends ExpectedException {
+
+ private static final String MESSAGE = "거리는 음수일 수 없습니다.";
+
+ public DistanceNotPositiveException() {
+ super(MESSAGE);
+ }
+}
diff --git a/src/main/java/subway/application/exception/ExpectedException.java b/src/main/java/subway/application/core/exception/ExpectedException.java
similarity index 76%
rename from src/main/java/subway/application/exception/ExpectedException.java
rename to src/main/java/subway/application/core/exception/ExpectedException.java
index 3b68391f3..b6953cbb7 100644
--- a/src/main/java/subway/application/exception/ExpectedException.java
+++ b/src/main/java/subway/application/core/exception/ExpectedException.java
@@ -1,4 +1,4 @@
-package subway.application.exception;
+package subway.application.core.exception;
public class ExpectedException extends RuntimeException {
diff --git a/src/main/java/subway/application/core/exception/FareCantCalculatedException.java b/src/main/java/subway/application/core/exception/FareCantCalculatedException.java
new file mode 100644
index 000000000..bd794dac5
--- /dev/null
+++ b/src/main/java/subway/application/core/exception/FareCantCalculatedException.java
@@ -0,0 +1,10 @@
+package subway.application.core.exception;
+
+public class FareCantCalculatedException extends ExpectedException {
+
+ private static final String MESSAGE = "해당하는 거리에 맞는 요금을 찾을 수 없습니다.";
+
+ public FareCantCalculatedException() {
+ super(MESSAGE);
+ }
+}
diff --git a/src/main/java/subway/application/exception/RouteNotConnectedException.java b/src/main/java/subway/application/core/exception/RouteNotConnectedException.java
similarity index 84%
rename from src/main/java/subway/application/exception/RouteNotConnectedException.java
rename to src/main/java/subway/application/core/exception/RouteNotConnectedException.java
index 56576ceca..1a7f76492 100644
--- a/src/main/java/subway/application/exception/RouteNotConnectedException.java
+++ b/src/main/java/subway/application/core/exception/RouteNotConnectedException.java
@@ -1,4 +1,4 @@
-package subway.application.exception;
+package subway.application.core.exception;
public class RouteNotConnectedException extends ExpectedException {
diff --git a/src/main/java/subway/application/exception/SectionConnectException.java b/src/main/java/subway/application/core/exception/SectionConnectException.java
similarity index 85%
rename from src/main/java/subway/application/exception/SectionConnectException.java
rename to src/main/java/subway/application/core/exception/SectionConnectException.java
index 024e854e2..d6286d5f4 100644
--- a/src/main/java/subway/application/exception/SectionConnectException.java
+++ b/src/main/java/subway/application/core/exception/SectionConnectException.java
@@ -1,4 +1,4 @@
-package subway.application.exception;
+package subway.application.core.exception;
public class SectionConnectException extends ExpectedException {
diff --git a/src/main/java/subway/application/exception/StationAlreadyExistsException.java b/src/main/java/subway/application/core/exception/StationAlreadyExistsException.java
similarity index 84%
rename from src/main/java/subway/application/exception/StationAlreadyExistsException.java
rename to src/main/java/subway/application/core/exception/StationAlreadyExistsException.java
index fcbccddd0..d9405bbbc 100644
--- a/src/main/java/subway/application/exception/StationAlreadyExistsException.java
+++ b/src/main/java/subway/application/core/exception/StationAlreadyExistsException.java
@@ -1,4 +1,4 @@
-package subway.application.exception;
+package subway.application.core.exception;
public class StationAlreadyExistsException extends ExpectedException {
diff --git a/src/main/java/subway/application/exception/StationConnectException.java b/src/main/java/subway/application/core/exception/StationConnectException.java
similarity index 84%
rename from src/main/java/subway/application/exception/StationConnectException.java
rename to src/main/java/subway/application/core/exception/StationConnectException.java
index 0f94fcf71..9ccc47d00 100644
--- a/src/main/java/subway/application/exception/StationConnectException.java
+++ b/src/main/java/subway/application/core/exception/StationConnectException.java
@@ -1,4 +1,4 @@
-package subway.application.exception;
+package subway.application.core.exception;
public class StationConnectException extends ExpectedException {
diff --git a/src/main/java/subway/application/exception/StationNotExistsException.java b/src/main/java/subway/application/core/exception/StationNotExistsException.java
similarity index 85%
rename from src/main/java/subway/application/exception/StationNotExistsException.java
rename to src/main/java/subway/application/core/exception/StationNotExistsException.java
index 352c156ba..6f5dadd8a 100644
--- a/src/main/java/subway/application/exception/StationNotExistsException.java
+++ b/src/main/java/subway/application/core/exception/StationNotExistsException.java
@@ -1,4 +1,4 @@
-package subway.application.exception;
+package subway.application.core.exception;
public class StationNotExistsException extends ExpectedException {
diff --git a/src/main/java/subway/application/exception/StationTooFarException.java b/src/main/java/subway/application/core/exception/StationTooFarException.java
similarity index 86%
rename from src/main/java/subway/application/exception/StationTooFarException.java
rename to src/main/java/subway/application/core/exception/StationTooFarException.java
index 9baf387ea..e7d8ccf26 100644
--- a/src/main/java/subway/application/exception/StationTooFarException.java
+++ b/src/main/java/subway/application/core/exception/StationTooFarException.java
@@ -1,4 +1,4 @@
-package subway.application.exception;
+package subway.application.core.exception;
public class StationTooFarException extends ExpectedException {
diff --git a/src/main/java/subway/application/core/service/JourneyService.java b/src/main/java/subway/application/core/service/JourneyService.java
new file mode 100644
index 000000000..3861f4094
--- /dev/null
+++ b/src/main/java/subway/application/core/service/JourneyService.java
@@ -0,0 +1,61 @@
+package subway.application.core.service;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+import subway.application.core.domain.Fare;
+import subway.application.core.domain.Line;
+import subway.application.core.domain.RouteMap;
+import subway.application.core.domain.Station;
+import subway.application.core.service.dto.in.JourneyCommand;
+import subway.application.core.service.dto.out.JourneyResult;
+import subway.application.core.service.dto.out.PathFindResult;
+import subway.application.core.service.dto.out.StationResult;
+import subway.application.port.LineRepository;
+import subway.application.port.PathFinder;
+import subway.application.port.StationRepository;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+@Validated
+@Transactional(readOnly = true)
+public class JourneyService {
+
+ private final StationRepository stationRepository;
+ private final LineRepository lineRepository;
+ private final PathFinder pathFinder;
+
+ public JourneyService(StationRepository stationRepository, LineRepository lineRepository, PathFinder pathFinder) {
+ this.stationRepository = stationRepository;
+ this.lineRepository = lineRepository;
+ this.pathFinder = pathFinder;
+ }
+
+ public JourneyResult findShortestJourney(@Valid JourneyCommand journeyCommand) {
+ List routeMaps = getAllRouteMaps();
+ PathFindResult result = findShortestPath(journeyCommand, routeMaps);
+ return new JourneyResult(mapToStationResults(result), result.getDistance(),
+ Fare.of(result.getDistance()));
+ }
+
+ private List mapToStationResults(PathFindResult result) {
+ return result.getShortestPath().stream()
+ .map(StationResult::new)
+ .collect(Collectors.toList());
+ }
+
+ private PathFindResult findShortestPath(JourneyCommand journeyCommand, List routeMaps) {
+ Station departure = stationRepository.findById(journeyCommand.getDeparture());
+ Station terminal = stationRepository.findById(journeyCommand.getTerminal());
+ return pathFinder.findShortestPath(routeMaps, departure, terminal);
+ }
+
+ private List getAllRouteMaps() {
+ return lineRepository.findAll().stream()
+ .map(Line::routeMap)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/subway/application/core/service/LinePropertyService.java b/src/main/java/subway/application/core/service/LinePropertyService.java
new file mode 100644
index 000000000..a312bf0a1
--- /dev/null
+++ b/src/main/java/subway/application/core/service/LinePropertyService.java
@@ -0,0 +1,53 @@
+package subway.application.core.service;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+import subway.application.core.domain.LineProperty;
+import subway.application.core.service.dto.in.IdCommand;
+import subway.application.core.service.dto.in.SaveLinePropertyCommand;
+import subway.application.core.service.dto.in.UpdateLinePropertyCommand;
+import subway.application.core.service.dto.out.LinePropertyResult;
+import subway.application.port.LinePropertyRepository;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+@Validated
+@Transactional
+public class LinePropertyService {
+
+ private final LinePropertyRepository linePropertyRepository;
+
+ public LinePropertyService(LinePropertyRepository linePropertyRepository) {
+ this.linePropertyRepository = linePropertyRepository;
+ }
+
+ public LinePropertyResult saveLineProperty(@Valid SaveLinePropertyCommand command) {
+ LineProperty lineProperty = linePropertyRepository.insert(command.toEntity());
+ return new LinePropertyResult(lineProperty);
+ }
+
+ public List findAllLineProperty() {
+ List allLineProperties = linePropertyRepository.findAll();
+ return allLineProperties.stream()
+ .map(lineProperty -> new LinePropertyResult(lineProperty.getId(),
+ lineProperty.getName(), lineProperty.getColor()))
+ .collect(Collectors.toList());
+ }
+
+ public LinePropertyResult findLinePropertyById(@Valid IdCommand command) {
+ LineProperty lineProperty = linePropertyRepository.findById(command.getId());
+ return new LinePropertyResult(lineProperty);
+ }
+
+ public void updateLineProperty(@Valid UpdateLinePropertyCommand command) {
+ linePropertyRepository.update(command.toEntity());
+ }
+
+ public void deleteLinePropertyById(@Valid IdCommand command) {
+ linePropertyRepository.deleteById(command.getId());
+ }
+}
diff --git a/src/main/java/subway/application/core/service/LineService.java b/src/main/java/subway/application/core/service/LineService.java
new file mode 100644
index 000000000..13da6c93b
--- /dev/null
+++ b/src/main/java/subway/application/core/service/LineService.java
@@ -0,0 +1,71 @@
+package subway.application.core.service;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+import subway.application.core.domain.Distance;
+import subway.application.core.domain.Line;
+import subway.application.core.domain.Section;
+import subway.application.core.service.dto.in.DeleteStationCommand;
+import subway.application.core.service.dto.in.EnrollStationCommand;
+import subway.application.core.service.dto.in.IdCommand;
+import subway.application.core.service.dto.out.StationResult;
+import subway.application.port.LineRepository;
+import subway.application.port.StationRepository;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Service
+@Validated
+@Transactional
+public class LineService {
+
+ private final LineRepository lineRepository;
+ private final StationRepository stationRepository;
+
+ public LineService(LineRepository lineRepository, StationRepository stationRepository) {
+ this.lineRepository = lineRepository;
+ this.stationRepository = stationRepository;
+ }
+
+ public void enrollStation(@Valid EnrollStationCommand command) {
+ Line line = lineRepository.findById(command.getLineId());
+ Section section = generateSection(command);
+ line.addSection(section);
+ lineRepository.insert(line);
+ }
+
+ private Section generateSection(EnrollStationCommand command) {
+ return new Section(
+ stationRepository.findById(command.getUpBound()),
+ stationRepository.findById(command.getDownBound()),
+ new Distance(command.getDistance())
+ );
+ }
+
+ public void deleteStation(@Valid DeleteStationCommand command) {
+ Line line = lineRepository.findById(command.getLineId());
+ line.deleteStation(stationRepository.findById(command.getStationId()));
+ lineRepository.insert(line);
+ }
+
+ public List findRouteMap(@Valid IdCommand command) {
+ Line line = lineRepository.findById(command.getId());
+ return makeStationResultsOf(line);
+ }
+
+ public Map> findAllRouteMap() {
+ List allLines = lineRepository.findAll();
+ return allLines.stream()
+ .collect(Collectors.toMap(Line::getName, this::makeStationResultsOf));
+ }
+
+ private List makeStationResultsOf(Line line) {
+ return line.routeMap().stations().stream()
+ .map(station -> new StationResult(station.getId(), station.getName()))
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/subway/application/core/service/StationService.java b/src/main/java/subway/application/core/service/StationService.java
new file mode 100644
index 000000000..f08d9b43e
--- /dev/null
+++ b/src/main/java/subway/application/core/service/StationService.java
@@ -0,0 +1,52 @@
+package subway.application.core.service;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+import subway.application.core.domain.Station;
+import subway.application.core.service.dto.in.IdCommand;
+import subway.application.core.service.dto.in.SaveStationCommand;
+import subway.application.core.service.dto.in.UpdateStationCommand;
+import subway.application.core.service.dto.out.StationResult;
+import subway.application.port.StationRepository;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+@Validated
+@Transactional
+public class StationService {
+
+ private final StationRepository stationRepository;
+
+ public StationService(StationRepository stationRepository) {
+ this.stationRepository = stationRepository;
+ }
+
+ public StationResult saveStation(@Valid SaveStationCommand command) {
+ Station station = stationRepository.insert(command.toEntity());
+ return new StationResult(station);
+ }
+
+ public StationResult findStationById(@Valid IdCommand command) {
+ return new StationResult(stationRepository.findById(command.getId()));
+ }
+
+ public List findAllStations() {
+ List stations = stationRepository.findAll();
+
+ return stations.stream()
+ .map(station -> new StationResult(station.getId(), station.getName()))
+ .collect(Collectors.toList());
+ }
+
+ public void updateStation(@Valid UpdateStationCommand command) {
+ stationRepository.update(command.toEntity());
+ }
+
+ public void deleteStationById(@Valid IdCommand command) {
+ stationRepository.deleteById(command.getId());
+ }
+}
diff --git a/src/main/java/subway/application/core/service/dto/in/DeleteStationCommand.java b/src/main/java/subway/application/core/service/dto/in/DeleteStationCommand.java
new file mode 100644
index 000000000..b33753827
--- /dev/null
+++ b/src/main/java/subway/application/core/service/dto/in/DeleteStationCommand.java
@@ -0,0 +1,24 @@
+package subway.application.core.service.dto.in;
+
+import javax.validation.constraints.NotNull;
+
+public class DeleteStationCommand {
+
+ @NotNull
+ private final Long lineId;
+ @NotNull
+ private final Long stationId;
+
+ public DeleteStationCommand(Long lineId, Long stationId) {
+ this.lineId = lineId;
+ this.stationId = stationId;
+ }
+
+ public Long getLineId() {
+ return lineId;
+ }
+
+ public Long getStationId() {
+ return stationId;
+ }
+}
diff --git a/src/main/java/subway/application/core/service/dto/in/EnrollStationCommand.java b/src/main/java/subway/application/core/service/dto/in/EnrollStationCommand.java
new file mode 100644
index 000000000..cb25bd5e5
--- /dev/null
+++ b/src/main/java/subway/application/core/service/dto/in/EnrollStationCommand.java
@@ -0,0 +1,39 @@
+package subway.application.core.service.dto.in;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Positive;
+
+public class EnrollStationCommand {
+
+ @NotNull
+ private final Long lineId;
+ @NotNull
+ private final Long upBound;
+ @NotNull
+ private final Long downBound;
+ @Positive
+ private final Integer distance;
+
+ public EnrollStationCommand(Long lineId, Long upBound, Long downBound, Integer distance) {
+ this.lineId = lineId;
+ this.upBound = upBound;
+ this.downBound = downBound;
+ this.distance = distance;
+ }
+
+ public Long getLineId() {
+ return lineId;
+ }
+
+ public Long getUpBound() {
+ return upBound;
+ }
+
+ public Long getDownBound() {
+ return downBound;
+ }
+
+ public Integer getDistance() {
+ return distance;
+ }
+}
diff --git a/src/main/java/subway/application/core/service/dto/in/IdCommand.java b/src/main/java/subway/application/core/service/dto/in/IdCommand.java
new file mode 100644
index 000000000..e6477c3e5
--- /dev/null
+++ b/src/main/java/subway/application/core/service/dto/in/IdCommand.java
@@ -0,0 +1,17 @@
+package subway.application.core.service.dto.in;
+
+import javax.validation.constraints.NotNull;
+
+public class IdCommand {
+
+ @NotNull
+ private final Long id;
+
+ public IdCommand(Long id) {
+ this.id = id;
+ }
+
+ public Long getId() {
+ return id;
+ }
+}
diff --git a/src/main/java/subway/application/core/service/dto/in/JourneyCommand.java b/src/main/java/subway/application/core/service/dto/in/JourneyCommand.java
new file mode 100644
index 000000000..0c4548d1d
--- /dev/null
+++ b/src/main/java/subway/application/core/service/dto/in/JourneyCommand.java
@@ -0,0 +1,25 @@
+package subway.application.core.service.dto.in;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+public class JourneyCommand {
+
+ @NotNull
+ private final Long departure;
+ @NotNull
+ private final Long terminal;
+
+ public JourneyCommand(Long departure, Long terminal) {
+ this.departure = departure;
+ this.terminal = terminal;
+ }
+
+ public Long getDeparture() {
+ return departure;
+ }
+
+ public Long getTerminal() {
+ return terminal;
+ }
+}
diff --git a/src/main/java/subway/application/core/service/dto/in/SaveLinePropertyCommand.java b/src/main/java/subway/application/core/service/dto/in/SaveLinePropertyCommand.java
new file mode 100644
index 000000000..522af3fba
--- /dev/null
+++ b/src/main/java/subway/application/core/service/dto/in/SaveLinePropertyCommand.java
@@ -0,0 +1,24 @@
+package subway.application.core.service.dto.in;
+
+import subway.application.core.domain.LineProperty;
+
+import javax.validation.constraints.NotEmpty;
+
+public class SaveLinePropertyCommand {
+
+ private final Long id;
+ @NotEmpty
+ private final String name;
+ @NotEmpty
+ private final String color;
+
+ public SaveLinePropertyCommand(String name, String color) {
+ this.id = null;
+ this.name = name;
+ this.color = color;
+ }
+
+ public LineProperty toEntity() {
+ return new LineProperty(id, name, color);
+ }
+}
diff --git a/src/main/java/subway/application/core/service/dto/in/SaveStationCommand.java b/src/main/java/subway/application/core/service/dto/in/SaveStationCommand.java
new file mode 100644
index 000000000..7424be30f
--- /dev/null
+++ b/src/main/java/subway/application/core/service/dto/in/SaveStationCommand.java
@@ -0,0 +1,21 @@
+package subway.application.core.service.dto.in;
+
+import subway.application.core.domain.Station;
+
+import javax.validation.constraints.NotEmpty;
+
+public class SaveStationCommand {
+
+ private final Long id;
+ @NotEmpty
+ private final String name;
+
+ public SaveStationCommand(String name) {
+ this.id = null;
+ this.name = name;
+ }
+
+ public Station toEntity() {
+ return new Station(id, name);
+ }
+}
diff --git a/src/main/java/subway/application/core/service/dto/in/UpdateLinePropertyCommand.java b/src/main/java/subway/application/core/service/dto/in/UpdateLinePropertyCommand.java
new file mode 100644
index 000000000..fad2abb50
--- /dev/null
+++ b/src/main/java/subway/application/core/service/dto/in/UpdateLinePropertyCommand.java
@@ -0,0 +1,26 @@
+package subway.application.core.service.dto.in;
+
+import subway.application.core.domain.LineProperty;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+public class UpdateLinePropertyCommand {
+
+ @NotNull
+ private final Long id;
+ @NotEmpty
+ private final String name;
+ @NotEmpty
+ private final String color;
+
+ public UpdateLinePropertyCommand(Long id, String name, String color) {
+ this.id = id;
+ this.name = name;
+ this.color = color;
+ }
+
+ public LineProperty toEntity() {
+ return new LineProperty(id, name, color);
+ }
+}
diff --git a/src/main/java/subway/application/core/service/dto/in/UpdateStationCommand.java b/src/main/java/subway/application/core/service/dto/in/UpdateStationCommand.java
new file mode 100644
index 000000000..9c615206e
--- /dev/null
+++ b/src/main/java/subway/application/core/service/dto/in/UpdateStationCommand.java
@@ -0,0 +1,23 @@
+package subway.application.core.service.dto.in;
+
+import subway.application.core.domain.Station;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+public class UpdateStationCommand {
+
+ @NotNull
+ private final Long id;
+ @NotEmpty
+ private final String name;
+
+ public UpdateStationCommand(Long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public Station toEntity() {
+ return new Station(id, name);
+ }
+}
diff --git a/src/main/java/subway/application/core/service/dto/out/JourneyResult.java b/src/main/java/subway/application/core/service/dto/out/JourneyResult.java
new file mode 100644
index 000000000..196ba4f87
--- /dev/null
+++ b/src/main/java/subway/application/core/service/dto/out/JourneyResult.java
@@ -0,0 +1,30 @@
+package subway.application.core.service.dto.out;
+
+import subway.application.core.domain.Station;
+
+import java.util.List;
+
+public class JourneyResult {
+
+ private final List path;
+ private final Double distance;
+ private final Integer fare;
+
+ public JourneyResult(List path, Double distance, Integer fare) {
+ this.path = path;
+ this.distance = distance;
+ this.fare = fare;
+ }
+
+ public List getPath() {
+ return path;
+ }
+
+ public Double getDistance() {
+ return distance;
+ }
+
+ public Integer getFare() {
+ return fare;
+ }
+}
diff --git a/src/main/java/subway/application/core/service/dto/out/LinePropertyResult.java b/src/main/java/subway/application/core/service/dto/out/LinePropertyResult.java
new file mode 100644
index 000000000..b769c662d
--- /dev/null
+++ b/src/main/java/subway/application/core/service/dto/out/LinePropertyResult.java
@@ -0,0 +1,34 @@
+package subway.application.core.service.dto.out;
+
+import subway.application.core.domain.LineProperty;
+
+public class LinePropertyResult {
+
+ private final Long id;
+ private final String name;
+ private final String color;
+
+ public LinePropertyResult(LineProperty lineProperty) {
+ this.id = lineProperty.getId();
+ this.name = lineProperty.getName();
+ this.color = lineProperty.getColor();
+ }
+
+ public LinePropertyResult(Long id, String name, String color) {
+ this.id = id;
+ this.name = name;
+ this.color = color;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getColor() {
+ return color;
+ }
+}
diff --git a/src/main/java/subway/application/core/service/dto/out/PathFindResult.java b/src/main/java/subway/application/core/service/dto/out/PathFindResult.java
new file mode 100644
index 000000000..952aa4ef8
--- /dev/null
+++ b/src/main/java/subway/application/core/service/dto/out/PathFindResult.java
@@ -0,0 +1,24 @@
+package subway.application.core.service.dto.out;
+
+import subway.application.core.domain.Station;
+
+import java.util.List;
+
+public class PathFindResult {
+
+ private final List shortestPath;
+ private final Double distance;
+
+ public PathFindResult(List shortestPath, Double distance) {
+ this.shortestPath = shortestPath;
+ this.distance = distance;
+ }
+
+ public List getShortestPath() {
+ return shortestPath;
+ }
+
+ public Double getDistance() {
+ return distance;
+ }
+}
diff --git a/src/main/java/subway/application/core/service/dto/out/StationResult.java b/src/main/java/subway/application/core/service/dto/out/StationResult.java
new file mode 100644
index 000000000..3273b94b0
--- /dev/null
+++ b/src/main/java/subway/application/core/service/dto/out/StationResult.java
@@ -0,0 +1,26 @@
+package subway.application.core.service.dto.out;
+
+import subway.application.core.domain.Station;
+
+public class StationResult {
+
+ private final Long id;
+ private final String name;
+
+ public StationResult(Station station) {
+ this(station.getId(), station.getName());
+ }
+
+ public StationResult(Long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/main/java/subway/application/domain/RouteMap.java b/src/main/java/subway/application/domain/RouteMap.java
deleted file mode 100644
index ab2ae62de..000000000
--- a/src/main/java/subway/application/domain/RouteMap.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package subway.application.domain;
-
-import subway.application.exception.CircularRouteException;
-import subway.application.exception.RouteNotConnectedException;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
-public class RouteMap {
-
- private final List routeMap;
-
- public RouteMap(List sections) {
- this.routeMap = routeOf(sections);
- }
-
- private List routeOf(List sections) {
- if (sections.isEmpty()) {
- return Collections.emptyList();
- }
- return linkStations(sections);
- }
-
- private List linkStations(List sections) {
- List stations = new ArrayList<>();
- Station indexStation = findFirstStation(sections);
- while (hasNextStation(sections, indexStation) && !isInnerCircle(sections, stations)) {
- stations.add(indexStation);
- indexStation = findNext(sections, indexStation);
- }
- stations.add(indexStation);
- validate(sections, stations);
- return stations;
- }
-
- private Station findFirstStation(List sections) {
- List endPoints = getEndPoints(sections);
-
- return endPoints.stream()
- .findAny()
- .orElseThrow(CircularRouteException::new);
- }
-
- private List getEndPoints(List sections) {
- List allUpBounds = sections.stream()
- .map(Section::getUpBound)
- .collect(Collectors.toList());
-
- List allDownBounds = sections.stream()
- .map(Section::getDownBound)
- .collect(Collectors.toList());
-
- allUpBounds.removeAll(allDownBounds);
- return allUpBounds;
- }
-
- private boolean hasNextStation(List sections, Station targetStation) {
- return sections.stream()
- .anyMatch(section -> section.getUpBound().equals(targetStation));
- }
-
- private boolean isInnerCircle(List sections, List stations) {
- int maxStationSize = sections.size() + 1;
- return maxStationSize < stations.size();
- }
-
- private Station findNext(List sections, Station targetStation) {
- return sections.stream()
- .filter(section -> section.getUpBound().equals(targetStation))
- .map(Section::getDownBound)
- .findAny()
- .orElseThrow();
- }
-
- private void validate(List sections, List stations) {
- int maxStationSize = sections.size() + 1;
- if (maxStationSize < stations.size()) {
- throw new CircularRouteException();
- }
- if (maxStationSize > stations.size()) {
- throw new RouteNotConnectedException();
- }
- }
-
- public List value() {
- return Collections.unmodifiableList(routeMap);
- }
-}
diff --git a/src/main/java/subway/application/exception/DistanceExceedException.java b/src/main/java/subway/application/exception/DistanceExceedException.java
deleted file mode 100644
index 9a78e32e1..000000000
--- a/src/main/java/subway/application/exception/DistanceExceedException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package subway.application.exception;
-
-public class DistanceExceedException extends ExpectedException {
-
- private static final String MESSAGE = "역 간의 거리는 양수여야 합니다.";
-
- public DistanceExceedException() {
- super(MESSAGE);
- }
-}
diff --git a/src/main/java/subway/application/repository/LinePropertyRepository.java b/src/main/java/subway/application/port/LinePropertyRepository.java
similarity index 75%
rename from src/main/java/subway/application/repository/LinePropertyRepository.java
rename to src/main/java/subway/application/port/LinePropertyRepository.java
index eb19d334b..3666bd94e 100644
--- a/src/main/java/subway/application/repository/LinePropertyRepository.java
+++ b/src/main/java/subway/application/port/LinePropertyRepository.java
@@ -1,6 +1,6 @@
-package subway.application.repository;
+package subway.application.port;
-import subway.application.domain.LineProperty;
+import subway.application.core.domain.LineProperty;
import java.util.List;
diff --git a/src/main/java/subway/application/repository/LineRepository.java b/src/main/java/subway/application/port/LineRepository.java
similarity index 55%
rename from src/main/java/subway/application/repository/LineRepository.java
rename to src/main/java/subway/application/port/LineRepository.java
index f02882307..08ceddb25 100644
--- a/src/main/java/subway/application/repository/LineRepository.java
+++ b/src/main/java/subway/application/port/LineRepository.java
@@ -1,12 +1,12 @@
-package subway.application.repository;
+package subway.application.port;
-import subway.application.domain.Line;
+import subway.application.core.domain.Line;
import java.util.List;
public interface LineRepository {
- void insert(Line line);
+ Line insert(Line line);
Line findById(Long linePropertyId);
diff --git a/src/main/java/subway/application/port/PathFinder.java b/src/main/java/subway/application/port/PathFinder.java
new file mode 100644
index 000000000..96d31bff9
--- /dev/null
+++ b/src/main/java/subway/application/port/PathFinder.java
@@ -0,0 +1,13 @@
+package subway.application.port;
+
+import org.springframework.stereotype.Component;
+import subway.application.core.domain.RouteMap;
+import subway.application.core.domain.Station;
+import subway.application.core.service.dto.out.PathFindResult;
+
+import java.util.List;
+
+public interface PathFinder {
+
+ PathFindResult findShortestPath(List routeMap, Station departure, Station terminal);
+}
diff --git a/src/main/java/subway/application/repository/StationRepository.java b/src/main/java/subway/application/port/StationRepository.java
similarity index 74%
rename from src/main/java/subway/application/repository/StationRepository.java
rename to src/main/java/subway/application/port/StationRepository.java
index fbc0f9552..da2b8ec47 100644
--- a/src/main/java/subway/application/repository/StationRepository.java
+++ b/src/main/java/subway/application/port/StationRepository.java
@@ -1,6 +1,6 @@
-package subway.application.repository;
+package subway.application.port;
-import subway.application.domain.Station;
+import subway.application.core.domain.Station;
import java.util.List;
diff --git a/src/main/java/subway/application/service/LinePropertyService.java b/src/main/java/subway/application/service/LinePropertyService.java
deleted file mode 100644
index 668790c64..000000000
--- a/src/main/java/subway/application/service/LinePropertyService.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package subway.application.service;
-
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import subway.application.domain.LineProperty;
-import subway.application.repository.LinePropertyRepository;
-import subway.presentation.dto.LineRequest;
-import subway.presentation.dto.LineResponse;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Service
-@Transactional
-public class LinePropertyService {
-
- private final LinePropertyRepository linePropertyRepository;
-
- public LinePropertyService(LinePropertyRepository linePropertyRepository) {
- this.linePropertyRepository = linePropertyRepository;
- }
-
- public LineResponse saveLine(LineRequest request) {
- LineProperty lineProperty = linePropertyRepository.insert(
- new LineProperty(null, request.getName(), request.getColor()));
- return LineResponse.of(lineProperty);
- }
-
- public List findLineResponses() {
- List allLineProperties = findLines();
- return allLineProperties.stream()
- .map(LineResponse::of)
- .collect(Collectors.toList());
- }
-
- public List findLines() {
- return linePropertyRepository.findAll();
- }
-
- public LineResponse findLineResponseById(Long id) {
- LineProperty lineProperty = linePropertyRepository.findById(id);
- return LineResponse.of(lineProperty);
- }
-
- public void updateLine(Long id, LineRequest lineUpdateRequest) {
- linePropertyRepository.update(new LineProperty(id, lineUpdateRequest.getName(), lineUpdateRequest.getColor()));
- }
-
- public void deleteLineById(Long id) {
- linePropertyRepository.deleteById(id);
- }
-}
diff --git a/src/main/java/subway/application/service/LineService.java b/src/main/java/subway/application/service/LineService.java
deleted file mode 100644
index 19c7b3554..000000000
--- a/src/main/java/subway/application/service/LineService.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package subway.application.service;
-
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import subway.application.domain.Distance;
-import subway.application.domain.Line;
-import subway.application.domain.Section;
-import subway.application.repository.LineRepository;
-import subway.application.repository.StationRepository;
-import subway.presentation.dto.StationEnrollRequest;
-import subway.presentation.dto.StationResponse;
-
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-@Service
-@Transactional
-public class LineService {
-
- private final LineRepository lineRepository;
- private final StationRepository stationRepository;
-
- public LineService(LineRepository lineRepository, StationRepository stationRepository) {
- this.lineRepository = lineRepository;
- this.stationRepository = stationRepository;
- }
-
- public void enrollStation(Long lineId, StationEnrollRequest request) {
- Line line = lineRepository.findById(lineId);
- Section section = new Section(
- stationRepository.findById(request.getUpBound()),
- stationRepository.findById(request.getDownBound()),
- new Distance(request.getDistance())
- );
- line.addSection(section);
- lineRepository.insert(line);
- }
-
- public void deleteStation(Long lineId, Long stationId) {
- Line line = lineRepository.findById(lineId);
-
- line.deleteStation(stationRepository.findById(stationId));
- lineRepository.insert(line);
- }
-
- public List findRouteMap(Long lineId) {
- Line line = lineRepository.findById(lineId);
- return makeRouteMapResponseOf(line);
- }
-
- public Map> findAllRouteMap() {
- List allLines = lineRepository.findAll();
-
- return allLines.stream()
- .collect(Collectors.toMap(Line::getName, this::makeRouteMapResponseOf));
- }
-
- private List makeRouteMapResponseOf(Line line) {
- return line.routeMap().value().stream()
- .map(station -> new StationResponse(station.getId(), station.getName()))
- .collect(Collectors.toList());
- }
-}
diff --git a/src/main/java/subway/application/service/StationService.java b/src/main/java/subway/application/service/StationService.java
deleted file mode 100644
index 8c167689b..000000000
--- a/src/main/java/subway/application/service/StationService.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package subway.application.service;
-
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import subway.application.domain.Station;
-import subway.application.repository.StationRepository;
-import subway.presentation.dto.StationRequest;
-import subway.presentation.dto.StationResponse;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Service
-@Transactional
-public class StationService {
-
- private final StationRepository stationRepository;
-
- public StationService(StationRepository stationRepository) {
- this.stationRepository = stationRepository;
- }
-
- public StationResponse saveStation(StationRequest stationRequest) {
- Station station = stationRepository.insert(new Station(null, stationRequest.getName()));
- return StationResponse.of(station);
- }
-
- public StationResponse findStationResponseById(Long id) {
- return StationResponse.of(stationRepository.findById(id));
- }
-
- public List findAllStationResponses() {
- List stations = stationRepository.findAll();
-
- return stations.stream()
- .map(StationResponse::of)
- .collect(Collectors.toList());
- }
-
- public void updateStation(Long id, StationRequest stationRequest) {
- stationRepository.update(new Station(id, stationRequest.getName()));
- }
-
- public void deleteStationById(Long id) {
- stationRepository.deleteById(id);
- }
-}
diff --git a/src/main/java/subway/config/SwaggerConfig.java b/src/main/java/subway/config/SwaggerConfig.java
new file mode 100644
index 000000000..42a37173b
--- /dev/null
+++ b/src/main/java/subway/config/SwaggerConfig.java
@@ -0,0 +1,50 @@
+package subway.config;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import org.springdoc.core.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SwaggerConfig {
+
+ @Bean
+ public GroupedOpenApi stationApi() {
+ return GroupedOpenApi.builder()
+ .group("STATION")
+ .pathsToMatch("/stations/**")
+ .build();
+ }
+
+ @Bean
+ public GroupedOpenApi linePropertyApi() {
+ return GroupedOpenApi.builder()
+ .group("LINE PROPERTY")
+ .pathsToMatch("/lines/**")
+ .build();
+ }
+
+ @Bean
+ public GroupedOpenApi lineApi() {
+ return GroupedOpenApi.builder()
+ .group("LINE")
+ .pathsToMatch("/subway/**")
+ .build();
+ }
+
+ @Bean
+ public GroupedOpenApi journeyApi() {
+ return GroupedOpenApi.builder()
+ .group("JOURNEY")
+ .pathsToMatch("/journey/**")
+ .build();
+ }
+
+ @Bean
+ public OpenAPI springShopOpenAPI() {
+ return new OpenAPI()
+ .info(new Info().title("subway-path API")
+ .description("지하철 노선도 미션 API입니다."));
+ }
+}
diff --git a/src/main/java/subway/config/WebMvcConfiguration.java b/src/main/java/subway/config/WebMvcConfiguration.java
new file mode 100644
index 000000000..0a76271e0
--- /dev/null
+++ b/src/main/java/subway/config/WebMvcConfiguration.java
@@ -0,0 +1,22 @@
+package subway.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import subway.presentation.LoggerInterceptor;
+
+@Configuration
+public class WebMvcConfiguration implements WebMvcConfigurer {
+
+ private final LoggerInterceptor loggerInterceptor;
+
+ public WebMvcConfiguration(LoggerInterceptor loggerInterceptor) {
+ this.loggerInterceptor = loggerInterceptor;
+ }
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(loggerInterceptor)
+ .addPathPatterns("/**");
+ }
+}
diff --git a/src/main/java/subway/persistence/dao/LinePropertyDao.java b/src/main/java/subway/infrastructure/dao/LineDao.java
similarity index 58%
rename from src/main/java/subway/persistence/dao/LinePropertyDao.java
rename to src/main/java/subway/infrastructure/dao/LineDao.java
index 6c3de0655..3c736edcf 100644
--- a/src/main/java/subway/persistence/dao/LinePropertyDao.java
+++ b/src/main/java/subway/infrastructure/dao/LineDao.java
@@ -1,10 +1,10 @@
-package subway.persistence.dao;
+package subway.infrastructure.dao;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;
-import subway.persistence.row.LinePropertyRow;
+import subway.infrastructure.entity.LineRow;
import javax.sql.DataSource;
import java.util.HashMap;
@@ -12,51 +12,51 @@
import java.util.Map;
@Repository
-public class LinePropertyDao {
+public class LineDao {
private final JdbcTemplate jdbcTemplate;
private final SimpleJdbcInsert insertAction;
- private final RowMapper rowMapper = (rs, rowNum) ->
- new LinePropertyRow(
+ private final RowMapper rowMapper = (rs, rowNum) ->
+ new LineRow(
rs.getLong("id"),
rs.getString("name"),
rs.getString("color")
);
- public LinePropertyDao(JdbcTemplate jdbcTemplate, DataSource dataSource) {
+ public LineDao(JdbcTemplate jdbcTemplate, DataSource dataSource) {
this.jdbcTemplate = jdbcTemplate;
this.insertAction = new SimpleJdbcInsert(dataSource)
- .withTableName("line_property")
+ .withTableName("line")
.usingGeneratedKeyColumns("id");
}
- public LinePropertyRow insert(LinePropertyRow row) {
+ public LineRow insert(LineRow row) {
Map params = new HashMap<>();
params.put("id", row.getId());
params.put("name", row.getName());
params.put("color", row.getColor());
Long lineId = insertAction.executeAndReturnKey(params).longValue();
- return new LinePropertyRow(lineId, row.getName(), row.getColor());
+ return new LineRow(lineId, row.getName(), row.getColor());
}
- public List selectAll() {
- String sql = "select id, name, color from line_property";
+ public List selectAll() {
+ String sql = "select id, name, color from line";
return jdbcTemplate.query(sql, rowMapper);
}
- public LinePropertyRow findById(Long id) {
- String sql = "select id, name, color from line_property WHERE id = ?";
+ public LineRow findById(Long id) {
+ String sql = "select id, name, color from line WHERE id = ?";
return jdbcTemplate.queryForObject(sql, rowMapper, id);
}
- public void update(LinePropertyRow row) {
- String sql = "update line_property set name = ?, color = ? where id = ?";
+ public void update(LineRow row) {
+ String sql = "update line set name = ?, color = ? where id = ?";
jdbcTemplate.update(sql, new Object[]{row.getName(), row.getColor(), row.getId()});
}
public void deleteById(Long id) {
- String sql = "delete from line_property where id = ?";
+ String sql = "delete from line where id = ?";
jdbcTemplate.update(sql, id);
}
}
diff --git a/src/main/java/subway/persistence/dao/SectionDao.java b/src/main/java/subway/infrastructure/dao/SectionDao.java
similarity index 76%
rename from src/main/java/subway/persistence/dao/SectionDao.java
rename to src/main/java/subway/infrastructure/dao/SectionDao.java
index fc509e963..1565fa61f 100644
--- a/src/main/java/subway/persistence/dao/SectionDao.java
+++ b/src/main/java/subway/infrastructure/dao/SectionDao.java
@@ -1,9 +1,9 @@
-package subway.persistence.dao;
+package subway.infrastructure.dao;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
-import subway.persistence.row.SectionRow;
+import subway.infrastructure.entity.SectionRow;
import java.util.List;
@@ -17,8 +17,8 @@ public class SectionDao {
private final RowMapper rowMapper = (rs, cn) -> new SectionRow(
rs.getLong("id"),
rs.getLong("line_id"),
- rs.getString("up_bound"),
- rs.getString("down_bound"),
+ rs.getLong("up_bound"),
+ rs.getLong("down_bound"),
rs.getInt("distance")
);
@@ -26,9 +26,9 @@ public SectionDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
- public List selectAllOfLinePropertyId(Long linePropertyId) {
+ public List selectAllOfLineId(Long lineId) {
String sectionSql = "select id, line_id, up_bound, down_bound, distance from section where line_id = ?";
- return jdbcTemplate.query(sectionSql, rowMapper, linePropertyId);
+ return jdbcTemplate.query(sectionSql, rowMapper, lineId);
}
public void insertAll(List rows) {
@@ -37,8 +37,8 @@ public void insertAll(List rows) {
jdbcTemplate.batchUpdate(sql, rows, BATCH_SIZE,
(ps, entity) -> {
ps.setLong(1, entity.getLineId());
- ps.setString(2, entity.getUpBound());
- ps.setString(3, entity.getDownBound());
+ ps.setLong(2, entity.getUpBound());
+ ps.setLong(3, entity.getDownBound());
ps.setInt(4, entity.getDistance());
});
}
diff --git a/src/main/java/subway/persistence/dao/StationDao.java b/src/main/java/subway/infrastructure/dao/StationDao.java
similarity index 74%
rename from src/main/java/subway/persistence/dao/StationDao.java
rename to src/main/java/subway/infrastructure/dao/StationDao.java
index 60a527a6c..625207bf1 100644
--- a/src/main/java/subway/persistence/dao/StationDao.java
+++ b/src/main/java/subway/infrastructure/dao/StationDao.java
@@ -1,4 +1,4 @@
-package subway.persistence.dao;
+package subway.infrastructure.dao;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
@@ -6,7 +6,7 @@
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;
-import subway.persistence.row.StationRow;
+import subway.infrastructure.entity.StationRow;
import javax.sql.DataSource;
import java.util.Collections;
@@ -41,34 +41,34 @@ public StationRow insert(StationRow row) {
}
public List selectAll() {
- String sql = "select * from STATION";
+ String sql = "select * from station";
return jdbcTemplate.query(sql, rowMapper);
}
public StationRow selectById(Long id) {
- String sql = "select * from STATION where id = ?";
+ String sql = "select * from station where id = ?";
return jdbcTemplate.queryForObject(sql, rowMapper, id);
}
- public Map selectKeyValueSetWhereNameIn(List names) {
- String inSql = String.join(",", Collections.nCopies(names.size(), "?"));
- String sql = String.format("select id, name from station where name in (%s)", inSql);
+ public Map selectKeyValueSetWhereIdIn(List ids) {
+ String inSql = String.join(",", Collections.nCopies(ids.size(), "?"));
+ String sql = String.format("select id, name from station where id in (%s)", inSql);
- List> nameIdKeyValue = jdbcTemplate.query(sql,
- (rs, cn) -> Map.entry(rs.getString("name"), rs.getLong("id")),
- names.toArray());
+ List> nameIdKeyValue = jdbcTemplate.query(sql,
+ (rs, cn) -> Map.entry(rs.getLong("id"), rs.getString("name")),
+ ids.toArray());
return nameIdKeyValue.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
public void update(StationRow row) {
- String sql = "update STATION set name = ? where id = ?";
+ String sql = "update station set name = ? where id = ?";
jdbcTemplate.update(sql, new Object[]{row.getName(), row.getId()});
}
public void deleteById(Long id) {
- String sql = "delete from STATION where id = ?";
+ String sql = "delete from station where id = ?";
jdbcTemplate.update(sql, id);
}
}
diff --git a/src/main/java/subway/persistence/row/LinePropertyRow.java b/src/main/java/subway/infrastructure/entity/LineRow.java
similarity index 73%
rename from src/main/java/subway/persistence/row/LinePropertyRow.java
rename to src/main/java/subway/infrastructure/entity/LineRow.java
index 85dcac4c5..2e67529d2 100644
--- a/src/main/java/subway/persistence/row/LinePropertyRow.java
+++ b/src/main/java/subway/infrastructure/entity/LineRow.java
@@ -1,12 +1,12 @@
-package subway.persistence.row;
+package subway.infrastructure.entity;
-public class LinePropertyRow {
+public class LineRow {
private final Long id;
private final String name;
private final String color;
- public LinePropertyRow(Long id, String name, String color) {
+ public LineRow(Long id, String name, String color) {
this.id = id;
this.name = name;
this.color = color;
diff --git a/src/main/java/subway/persistence/row/SectionRow.java b/src/main/java/subway/infrastructure/entity/SectionRow.java
similarity index 51%
rename from src/main/java/subway/persistence/row/SectionRow.java
rename to src/main/java/subway/infrastructure/entity/SectionRow.java
index 6faaa406e..dd5e4bad0 100644
--- a/src/main/java/subway/persistence/row/SectionRow.java
+++ b/src/main/java/subway/infrastructure/entity/SectionRow.java
@@ -1,18 +1,18 @@
-package subway.persistence.row;
+package subway.infrastructure.entity;
public class SectionRow {
private final Long id;
private final Long lineId;
- private final String left;
- private final String right;
+ private final Long upBound;
+ private final Long downBound;
private final Integer distance;
- public SectionRow(Long id, Long lineId, String left, String right, Integer distance) {
+ public SectionRow(Long id, Long lineId, Long upBound, Long downBound, Integer distance) {
this.id = id;
this.lineId = lineId;
- this.left = left;
- this.right = right;
+ this.upBound = upBound;
+ this.downBound = downBound;
this.distance = distance;
}
@@ -24,12 +24,12 @@ public Long getLineId() {
return lineId;
}
- public String getUpBound() {
- return left;
+ public Long getUpBound() {
+ return upBound;
}
- public String getDownBound() {
- return right;
+ public Long getDownBound() {
+ return downBound;
}
public Integer getDistance() {
diff --git a/src/main/java/subway/persistence/row/StationRow.java b/src/main/java/subway/infrastructure/entity/StationRow.java
similarity index 88%
rename from src/main/java/subway/persistence/row/StationRow.java
rename to src/main/java/subway/infrastructure/entity/StationRow.java
index d4fe77371..81625b15e 100644
--- a/src/main/java/subway/persistence/row/StationRow.java
+++ b/src/main/java/subway/infrastructure/entity/StationRow.java
@@ -1,4 +1,4 @@
-package subway.persistence.row;
+package subway.infrastructure.entity;
public class StationRow {
diff --git a/src/main/java/subway/infrastructure/graph/JgraphtPathFinder.java b/src/main/java/subway/infrastructure/graph/JgraphtPathFinder.java
new file mode 100644
index 000000000..1aa9d58a3
--- /dev/null
+++ b/src/main/java/subway/infrastructure/graph/JgraphtPathFinder.java
@@ -0,0 +1,44 @@
+package subway.infrastructure.graph;
+
+import org.jgrapht.GraphPath;
+import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
+import org.jgrapht.graph.DefaultWeightedEdge;
+import org.jgrapht.graph.WeightedMultigraph;
+import org.springframework.stereotype.Component;
+import subway.application.core.domain.RouteMap;
+import subway.application.core.domain.Section;
+import subway.application.core.domain.Station;
+import subway.application.core.service.dto.out.PathFindResult;
+import subway.application.port.PathFinder;
+
+import java.util.List;
+
+@Component
+public class JgraphtPathFinder implements PathFinder {
+
+ @Override
+ public PathFindResult findShortestPath(List routeMap, Station departure, Station terminal) {
+ WeightedMultigraph graph = setupGraph(routeMap);
+ DijkstraShortestPath shortestPath = new DijkstraShortestPath<>(graph);
+ GraphPath path = shortestPath.getPath(departure, terminal);
+ return new PathFindResult(path.getVertexList(), path.getWeight());
+ }
+
+ private WeightedMultigraph setupGraph(List routeMap) {
+ WeightedMultigraph graph = new WeightedMultigraph<>(DefaultWeightedEdge.class);
+ routeMap.stream()
+ .map(RouteMap::values)
+ .forEach(stations -> applyRouteToGraph(graph, stations));
+ return graph;
+ }
+
+ private void applyRouteToGraph(WeightedMultigraph graph, List sections) {
+ sections.forEach(section -> {
+ Station upBound = section.getUpBound();
+ Station downBound = section.getDownBound();
+ graph.addVertex(upBound);
+ graph.addVertex(downBound);
+ graph.setEdgeWeight(graph.addEdge(upBound, downBound), section.getDistance().value());
+ });
+ }
+}
diff --git a/src/main/java/subway/infrastructure/repository/LinePersistenceAdapter.java b/src/main/java/subway/infrastructure/repository/LinePersistenceAdapter.java
new file mode 100644
index 000000000..ce28ef831
--- /dev/null
+++ b/src/main/java/subway/infrastructure/repository/LinePersistenceAdapter.java
@@ -0,0 +1,105 @@
+package subway.infrastructure.repository;
+
+import org.springframework.stereotype.Repository;
+import subway.application.port.LineRepository;
+import subway.application.core.domain.Distance;
+import subway.application.core.domain.Line;
+import subway.application.core.domain.LineProperty;
+import subway.application.core.domain.Section;
+import subway.application.core.domain.Station;
+import subway.infrastructure.dao.LineDao;
+import subway.infrastructure.dao.SectionDao;
+import subway.infrastructure.dao.StationDao;
+import subway.infrastructure.entity.LineRow;
+import subway.infrastructure.entity.SectionRow;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Repository
+public class LinePersistenceAdapter implements LineRepository {
+
+ private final SectionDao sectionDao;
+ private final StationDao stationDao;
+ private final LineDao lineDao;
+
+ public LinePersistenceAdapter(SectionDao sectionDao, LineDao lineDao, StationDao stationDao) {
+ this.sectionDao = sectionDao;
+ this.stationDao = stationDao;
+ this.lineDao = lineDao;
+ }
+
+ public Line findById(Long lineId) {
+ List sectionEntities = sectionDao.selectAllOfLineId(lineId);
+ LineRow lineRow = lineDao.findById(lineId);
+ List sections = generateSectionsFrom(sectionEntities);
+
+ return new Line(new LineProperty(lineRow.getId(), lineRow.getName(),
+ lineRow.getColor()), sections);
+ }
+
+ private List generateSectionsFrom(List sectionEntities) {
+ Map stationIdNameSet = getStationIdNameSet(sectionEntities);
+ return sectionEntities.stream()
+ .map(sectionRow -> new Section(
+ new Station(sectionRow.getUpBound(), stationIdNameSet.get(sectionRow.getUpBound())),
+ new Station(sectionRow.getDownBound(), stationIdNameSet.get(sectionRow.getDownBound())),
+ new Distance(sectionRow.getDistance())))
+ .collect(Collectors.toList());
+ }
+
+ private Map getStationIdNameSet(List sectionRows) {
+ if (sectionRows.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ return stationDao.selectKeyValueSetWhereIdIn(getStationIds(sectionRows));
+ }
+
+ private List getStationIds(List sectionEntities) {
+ Set stationNames = new HashSet<>();
+ for (SectionRow sectionRow : sectionEntities) {
+ stationNames.add(sectionRow.getUpBound());
+ stationNames.add(sectionRow.getDownBound());
+ }
+ return new ArrayList<>(stationNames);
+ }
+
+ public List findAll() {
+ List lineRows = lineDao.selectAll();
+ List sectionRows = sectionDao.selectAll();
+ Map stationIds = getStationIdNameSet(sectionRows);
+
+ return lineRows.stream()
+ .map(lineRow -> new Line(
+ new LineProperty(lineRow.getId(), lineRow.getName(), lineRow.getColor()),
+ findSectionsWithLineId(sectionRows, stationIds, lineRow)))
+ .collect(Collectors.toList());
+ }
+
+ private List findSectionsWithLineId(List sectionRows,
+ Map stationIds, LineRow lineRow) {
+ return sectionRows.stream()
+ .filter(sectionRow -> lineRow.getId().equals(sectionRow.getLineId()))
+ .map(sectionRow -> new Section(
+ new Station(sectionRow.getUpBound(), stationIds.get(sectionRow.getUpBound())),
+ new Station(sectionRow.getDownBound(), stationIds.get(sectionRow.getDownBound())),
+ new Distance(sectionRow.getDistance())))
+ .collect(Collectors.toList());
+ }
+
+ public Line insert(Line line) {
+ List sectionRows = line.getSections().stream()
+ .map(section -> new SectionRow(null, line.getId(), section.getUpBound().getId(),
+ section.getDownBound().getId(), section.getDistance().value()))
+ .collect(Collectors.toList());
+
+ sectionDao.removeSections(line.getId());
+ sectionDao.insertAll(sectionRows);
+ return findById(line.getId());
+ }
+}
diff --git a/src/main/java/subway/infrastructure/repository/LinePropertyPersistenceAdapter.java b/src/main/java/subway/infrastructure/repository/LinePropertyPersistenceAdapter.java
new file mode 100644
index 000000000..a3d93dee1
--- /dev/null
+++ b/src/main/java/subway/infrastructure/repository/LinePropertyPersistenceAdapter.java
@@ -0,0 +1,47 @@
+package subway.infrastructure.repository;
+
+import org.springframework.stereotype.Repository;
+import subway.application.core.domain.LineProperty;
+import subway.application.port.LinePropertyRepository;
+import subway.infrastructure.dao.LineDao;
+import subway.infrastructure.entity.LineRow;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Repository
+public class LinePropertyPersistenceAdapter implements LinePropertyRepository {
+
+ private final LineDao lineDao;
+
+ public LinePropertyPersistenceAdapter(LineDao lineDao) {
+ this.lineDao = lineDao;
+ }
+
+ public LineProperty insert(LineProperty lineProperty) {
+ LineRow row = lineDao.insert(
+ new LineRow(lineProperty.getId(), lineProperty.getName(), lineProperty.getColor()));
+ return new LineProperty(row.getId(), row.getName(), row.getColor());
+ }
+
+ public List findAll() {
+ List rows = lineDao.selectAll();
+
+ return rows.stream()
+ .map(row -> new LineProperty(row.getId(), row.getName(), row.getColor()))
+ .collect(Collectors.toList());
+ }
+
+ public LineProperty findById(Long id) {
+ LineRow row = lineDao.findById(id);
+ return new LineProperty(row.getId(), row.getName(), row.getColor());
+ }
+
+ public void update(LineProperty lineProperty) {
+ lineDao.update(new LineRow(lineProperty.getId(), lineProperty.getName(), lineProperty.getColor()));
+ }
+
+ public void deleteById(Long id) {
+ lineDao.deleteById(id);
+ }
+}
diff --git a/src/main/java/subway/persistence/repository/H2StationRepository.java b/src/main/java/subway/infrastructure/repository/StationPersistenceAdapter.java
similarity index 73%
rename from src/main/java/subway/persistence/repository/H2StationRepository.java
rename to src/main/java/subway/infrastructure/repository/StationPersistenceAdapter.java
index 26be55632..fe222882f 100644
--- a/src/main/java/subway/persistence/repository/H2StationRepository.java
+++ b/src/main/java/subway/infrastructure/repository/StationPersistenceAdapter.java
@@ -1,20 +1,20 @@
-package subway.persistence.repository;
+package subway.infrastructure.repository;
import org.springframework.stereotype.Repository;
-import subway.application.domain.Station;
-import subway.application.repository.StationRepository;
-import subway.persistence.dao.StationDao;
-import subway.persistence.row.StationRow;
+import subway.application.core.domain.Station;
+import subway.application.port.StationRepository;
+import subway.infrastructure.dao.StationDao;
+import subway.infrastructure.entity.StationRow;
import java.util.List;
import java.util.stream.Collectors;
@Repository
-public class H2StationRepository implements StationRepository {
+public class StationPersistenceAdapter implements StationRepository {
private final StationDao stationDao;
- public H2StationRepository(StationDao stationDao) {
+ public StationPersistenceAdapter(StationDao stationDao) {
this.stationDao = stationDao;
}
diff --git a/src/main/java/subway/persistence/repository/H2LinePropertyRepository.java b/src/main/java/subway/persistence/repository/H2LinePropertyRepository.java
deleted file mode 100644
index 8f3446305..000000000
--- a/src/main/java/subway/persistence/repository/H2LinePropertyRepository.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package subway.persistence.repository;
-
-import org.springframework.stereotype.Repository;
-import subway.application.domain.LineProperty;
-import subway.application.repository.LinePropertyRepository;
-import subway.persistence.dao.LinePropertyDao;
-import subway.persistence.row.LinePropertyRow;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Repository
-public class H2LinePropertyRepository implements LinePropertyRepository {
-
- private final LinePropertyDao linePropertyDao;
-
- public H2LinePropertyRepository(LinePropertyDao linePropertyDao) {
- this.linePropertyDao = linePropertyDao;
- }
-
- public LineProperty insert(LineProperty lineProperty) {
- LinePropertyRow row = linePropertyDao.insert(
- new LinePropertyRow(lineProperty.getId(), lineProperty.getName(), lineProperty.getColor()));
-
- return new LineProperty(row.getId(), row.getName(), row.getColor());
- }
-
- public List findAll() {
- List rows = linePropertyDao.selectAll();
-
- return rows.stream()
- .map(row -> new LineProperty(row.getId(), row.getName(), row.getColor()))
- .collect(Collectors.toList());
- }
-
- public LineProperty findById(Long id) {
- LinePropertyRow row = linePropertyDao.findById(id);
-
- return new LineProperty(row.getId(), row.getName(), row.getColor());
- }
-
- public void update(LineProperty lineProperty) {
- linePropertyDao.update(
- new LinePropertyRow(lineProperty.getId(), lineProperty.getName(), lineProperty.getColor()));
- }
-
- public void deleteById(Long id) {
- linePropertyDao.deleteById(id);
- }
-}
diff --git a/src/main/java/subway/persistence/repository/H2LineRepository.java b/src/main/java/subway/persistence/repository/H2LineRepository.java
deleted file mode 100644
index f31993914..000000000
--- a/src/main/java/subway/persistence/repository/H2LineRepository.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package subway.persistence.repository;
-
-import org.springframework.stereotype.Repository;
-import subway.application.repository.LineRepository;
-import subway.application.domain.Distance;
-import subway.application.domain.Line;
-import subway.application.domain.LineProperty;
-import subway.application.domain.Section;
-import subway.application.domain.Station;
-import subway.persistence.dao.LinePropertyDao;
-import subway.persistence.dao.SectionDao;
-import subway.persistence.dao.StationDao;
-import subway.persistence.row.LinePropertyRow;
-import subway.persistence.row.SectionRow;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-@Repository
-public class H2LineRepository implements LineRepository {
-
- private final SectionDao sectionDao;
- private final StationDao stationDao;
- private final LinePropertyDao linePropertyDao;
-
- public H2LineRepository(SectionDao sectionDao, LinePropertyDao linePropertyDao, StationDao stationDao) {
- this.sectionDao = sectionDao;
- this.stationDao = stationDao;
- this.linePropertyDao = linePropertyDao;
- }
-
- public Line findById(Long linePropertyId) {
- List sectionEntities = sectionDao.selectAllOfLinePropertyId(linePropertyId);
- LinePropertyRow linePropertyRow = linePropertyDao.findById(linePropertyId);
-
- Map stationIds = getStationNameIdSet(sectionEntities);
- List sections = sectionEntities.stream()
- .map(sectionRow -> new Section(
- new Station(stationIds.get(sectionRow.getUpBound()), sectionRow.getUpBound()),
- new Station(stationIds.get(sectionRow.getDownBound()), sectionRow.getDownBound()),
- new Distance(sectionRow.getDistance())
- )).collect(Collectors.toList());
-
- return new Line(new LineProperty(linePropertyRow.getId(), linePropertyRow.getName(),
- linePropertyRow.getColor()), sections);
- }
-
- private Map getStationNameIdSet(List sectionRows) {
- if (sectionRows.isEmpty()) {
- return Collections.emptyMap();
- }
- return stationDao.selectKeyValueSetWhereNameIn(getStationNames(sectionRows));
- }
-
- private List getStationNames(List sectionEntities) {
- Set stationNames = new HashSet<>();
- for (SectionRow sectionRow : sectionEntities) {
- stationNames.add(sectionRow.getUpBound());
- stationNames.add(sectionRow.getDownBound());
- }
- return new ArrayList<>(stationNames);
- }
-
- public List findAll() {
- List linePropertyRows = linePropertyDao.selectAll();
- List sectionRows = sectionDao.selectAll();
- Map stationIds = getStationNameIdSet(sectionRows);
-
- return linePropertyRows.stream()
- .map(propertyRow -> new Line(
- new LineProperty(propertyRow.getId(), propertyRow.getName(), propertyRow.getColor()),
- findSectionsHasSamePropertyId(sectionRows, stationIds, propertyRow))
- ).collect(Collectors.toList());
- }
-
- private List findSectionsHasSamePropertyId(List sectionRows,
- Map stationIds, LinePropertyRow propertyRow) {
- return sectionRows.stream()
- .filter(sectionRow -> propertyRow.getId().equals(sectionRow.getLineId()))
- .map(sectionRow -> new Section(
- new Station(stationIds.get(sectionRow.getUpBound()), sectionRow.getUpBound()),
- new Station(stationIds.get(sectionRow.getDownBound()), sectionRow.getDownBound()),
- new Distance(sectionRow.getDistance())
- )).collect(Collectors.toList());
- }
-
- public void insert(Line line) {
- List sectionRows = line.getSections().stream()
- .map(section -> new SectionRow(null, line.getId(), section.getUpBound().getName(),
- section.getDownBound().getName(), section.getDistance().value()))
- .collect(Collectors.toList());
-
- sectionDao.removeSections(line.getId());
- sectionDao.insertAll(sectionRows);
- }
-}
diff --git a/src/main/java/subway/presentation/advice/ExceptionAdvice.java b/src/main/java/subway/presentation/ExceptionAdvice.java
similarity index 78%
rename from src/main/java/subway/presentation/advice/ExceptionAdvice.java
rename to src/main/java/subway/presentation/ExceptionAdvice.java
index 015becbc0..755bafa1a 100644
--- a/src/main/java/subway/presentation/advice/ExceptionAdvice.java
+++ b/src/main/java/subway/presentation/ExceptionAdvice.java
@@ -1,15 +1,16 @@
-package subway.presentation.advice;
+package subway.presentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
-import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
-import subway.application.exception.ExpectedException;
+import subway.application.core.exception.ExpectedException;
import subway.presentation.dto.ExceptionResponse;
+import javax.validation.ConstraintDeclarationException;
+import javax.validation.ConstraintViolationException;
import java.sql.SQLException;
@RestControllerAdvice
@@ -22,10 +23,10 @@ public ResponseEntity dataException(DataAccessException e) {
logger.warn(e.getMessage(), e);
return ResponseEntity.badRequest()
- .build();
+ .body(new ExceptionResponse("유효하지 않은 입력입니다."));
}
- @ExceptionHandler(ExpectedException.class)
+ @ExceptionHandler({ExpectedException.class, ConstraintViolationException.class})
public ResponseEntity expectedException(ExpectedException e) {
logger.warn(e.getMessage(), e);
diff --git a/src/main/java/subway/presentation/LoggerInterceptor.java b/src/main/java/subway/presentation/LoggerInterceptor.java
new file mode 100644
index 000000000..f7b7186c7
--- /dev/null
+++ b/src/main/java/subway/presentation/LoggerInterceptor.java
@@ -0,0 +1,32 @@
+package subway.presentation;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Component
+public class LoggerInterceptor implements HandlerInterceptor {
+
+ private static final Logger logger = LoggerFactory.getLogger(LoggerInterceptor.class);
+
+ private static final String REQUEST_LOG_FORMAT = "[REQUEST][%s][%s]";
+ private static final String RESPONSE_LOG_FORMAT = "[RESPONSE][STATUS CODE : %d]";
+
+ @Override
+ public boolean preHandle(HttpServletRequest request,
+ HttpServletResponse response, Object handler) {
+ logger.info(String.format(REQUEST_LOG_FORMAT, request.getMethod(), request.getRequestURI()));
+ return true;
+ }
+
+
+ @Override
+ public void afterCompletion(HttpServletRequest request,
+ HttpServletResponse response, Object handler, Exception ex) {
+ logger.info(String.format(RESPONSE_LOG_FORMAT, response.getStatus()));
+ }
+}
diff --git a/src/main/java/subway/presentation/controller/JourneyController.java b/src/main/java/subway/presentation/controller/JourneyController.java
new file mode 100644
index 000000000..3d2462f12
--- /dev/null
+++ b/src/main/java/subway/presentation/controller/JourneyController.java
@@ -0,0 +1,54 @@
+package subway.presentation.controller;
+
+import io.swagger.v3.oas.annotations.Operation;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import subway.application.core.domain.Station;
+import subway.application.core.service.JourneyService;
+import subway.application.core.service.dto.in.JourneyCommand;
+import subway.application.core.service.dto.out.JourneyResult;
+import subway.application.core.service.dto.out.StationResult;
+import subway.presentation.dto.JourneyRequest;
+import subway.presentation.dto.JourneyResponse;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/journey")
+public class JourneyController {
+
+ private final JourneyService journeyService;
+
+ public JourneyController(JourneyService journeyService) {
+ this.journeyService = journeyService;
+ }
+
+ @PostMapping
+ @Operation(summary = "make journey", description = "목적지까지의 최단경로/금액/거리 반환")
+ public ResponseEntity makeJourney(@RequestBody JourneyRequest request) {
+ JourneyResult result = journeyService.findShortestJourney(
+ new JourneyCommand(request.getDeparture(), request.getTerminal()));
+ JourneyResponse response = makeJourneyResponseFor(result);
+
+ return ResponseEntity.ok(response);
+ }
+
+ private JourneyResponse makeJourneyResponseFor(JourneyResult result) {
+ return new JourneyResponse(
+ collectStationNames(result),
+ result.getDistance(),
+ result.getFare()
+ );
+ }
+
+ private List collectStationNames(JourneyResult result) {
+ return result.getPath().stream()
+ .map(StationResult::getName)
+ .collect(Collectors.toList());
+ }
+}
+
diff --git a/src/main/java/subway/presentation/controller/LineController.java b/src/main/java/subway/presentation/controller/LineController.java
index 5d3b80147..a8174b6f6 100644
--- a/src/main/java/subway/presentation/controller/LineController.java
+++ b/src/main/java/subway/presentation/controller/LineController.java
@@ -1,5 +1,6 @@
package subway.presentation.controller;
+import io.swagger.v3.oas.annotations.Operation;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -9,13 +10,18 @@
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
-import subway.application.service.LineService;
+import subway.application.core.service.LineService;
+import subway.application.core.service.dto.in.DeleteStationCommand;
+import subway.application.core.service.dto.in.EnrollStationCommand;
+import subway.application.core.service.dto.in.IdCommand;
+import subway.application.core.service.dto.out.StationResult;
import subway.presentation.dto.StationEnrollRequest;
import subway.presentation.dto.StationResponse;
import java.net.URI;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
@RestController
@RequestMapping("/subway")
@@ -28,26 +34,44 @@ public LineController(LineService lineService) {
}
@PostMapping("/{lineId}")
+ @Operation(summary = "enroll station", description = "노선에 역 추가")
public ResponseEntity enrollStation(@PathVariable Long lineId,
@RequestBody StationEnrollRequest request) {
- lineService.enrollStation(lineId, request);
+ lineService.enrollStation(
+ new EnrollStationCommand(lineId, request.getUpBound(), request.getDownBound(), request.getDistance()));
+
return ResponseEntity.created(URI.create("/lines/" + lineId)).build();
}
- @DeleteMapping("/{lineId}/{stationId}")
+ @DeleteMapping("/{lineId}/stations/{stationId}")
+ @Operation(summary = "delete station", description = "노선에서 역 제거")
public ResponseEntity deleteStation(@PathVariable Long lineId, @PathVariable Long stationId) {
- lineService.deleteStation(lineId, stationId);
+ lineService.deleteStation(new DeleteStationCommand(lineId, stationId));
+
return ResponseEntity.status(HttpStatus.NO_CONTENT)
.header("Location", "/line/" + lineId).build();
}
@GetMapping("/{lineId}")
+ @Operation(summary = "get route map", description = "노선도 반환")
public ResponseEntity> getRouteMap(@PathVariable Long lineId) {
- return ResponseEntity.ok(lineService.findRouteMap(lineId));
+ List results = lineService.findRouteMap(new IdCommand(lineId));
+ List responses = results.stream()
+ .map(result -> new StationResponse(result.getId(), result.getName()))
+ .collect(Collectors.toList());
+
+ return ResponseEntity.ok(responses);
}
@GetMapping
+ @Operation(summary = "get all route maps", description = "모든 노선도 반환")
public ResponseEntity