ã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã«ã¯ã質åãã¢ããªã±ãŒã·ã§ã³ãªã©ãè€éãªå€æ®µéã®å ¥åã䌎ããã©ãŒã ããããŸãããã®ãããªæ©èœã®èšèšã¯ãéåžžãéçºè ã«ãšã£ãŠé çã®çš®ã«ãªããŸããç»é¢éã§å€§éã®ããŒã¿ã転éãããããŒããªã³ã¯ã圢æãããŸããã€ãŸãããã®ããŒã¿ã誰ã«ã誰ã«ãã©ã®é åºã§éä¿¡ãã次ã«ã©ã®ç»é¢ãéããã§ãã
ãã®èšäºã§ã¯ãã¹ããããã€ã¹ãããã®æ©èœã®äœæ¥ãæŽçããããã®äŸ¿å©ãªæ¹æ³ãå ±æããŸãããã®å©ããåããŠãç»é¢éã®æ¥ç¶ãæå°éã«æããã¹ãããã®é åºãç°¡åã«å€æŽããããšãã§ããŸãïŒæ°ããç»é¢ãè¿œå ãããããã®é åºãšãŠãŒã¶ãŒã«è¡šç€ºããããžãã¯ãå€æŽããŸãã
*ãã®èšäºã®ãæ©èœããšããèšèã¯ãè«ççã«æ¥ç¶ããããŠãŒã¶ãŒã«ãšã£ãŠ1ã€ã®æ©èœãè¡šãã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã®äžé£ã®ç»é¢ãæå³ããŸãã
éåžžãã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã§è³ªå祚ã«èšå ¥ããã¢ããªã±ãŒã·ã§ã³ãéä¿¡ããããšã¯ãããã€ãã®é£ç¶ããç»é¢ã§æ§æãããŸããããç»é¢ã®ããŒã¿ãå¥ã®ç»é¢ã§å¿ èŠã«ãªãå Žåããããåçã«ãã£ãŠã¹ããããã§ãŒã³ãå€ããå ŽåããããŸãããããã£ãŠããŠãŒã¶ãŒãããŒã¿ãããã©ãããã§ä¿åããŠãåŸã§ããã»ã¹ã«æ»ãããšãã§ããããã«ãããšäŸ¿å©ã§ãã
å€ãã®ç»é¢ãååšããå¯èœæ§ããããŸãããå®éã«ã¯ããŠãŒã¶ãŒã¯1ã€ã®å€§ããªãªããžã§ã¯ãã«ããŒã¿ãå ¥åããŸãããã®èšäºã§ã¯ã1ã€ã®ã·ããªãªã§ããäžé£ã®ç»é¢ã䜿çšããŠäœæ¥ã䟿å©ã«æŽçããæ¹æ³ã説æããŸãã
ãŠãŒã¶ãŒãä»äºã«å¿åããŠãã©ãŒã ã«èšå ¥ããŠãããšããŸããããéäžã§äžæããå Žåãå ¥åããããŒã¿ã¯äžæžãã«ä¿åãããŸãããŠãŒã¶ãŒãèšå ¥ã«æ»ããšããã©ããã®æ å ±ãèªåçã«è³ªåã®ãã£ãŒã«ãã«çœ®ãæããããŸãããŠãŒã¶ãŒã¯ãã¹ãŠãæåããèšå ¥ããå¿ èŠã¯ãããŸããã
ãŠãŒã¶ãŒã質åç¥šå šäœã«èšå ¥ãããšãåçããµãŒããŒã«éä¿¡ãããŸãã
ã¢ã³ã±ãŒãã®å 容ã¯æ¬¡ã®ãšããã§ãã
- ã¹ããã1-ååãæè²ã®çš®é¡ãä»äºã®çµéšã
- ã¹ããã2-ç 究ã®å Žæ
- ã¹ããã3-ããªãèªèº«ã«ã€ããŠã®ä»äºãŸãã¯ãšãã»ã€ã®å Žæã
- ã¹ããã4-æ¬ å¡ãé¢å¿ãæã£ãŠããçç±ã
ã¢ã³ã±ãŒãã¯ããŠãŒã¶ãŒãæè²ãä»äºã®çµéšããããã©ããã«ãã£ãŠå€ãããŸããæè²ããªãå Žåã¯ãåŠç¿å Žæãåããã¹ããããé€å€ããŸããä»äºã®çµéšããªãå Žåã¯ããŠãŒã¶ãŒã«èªåèªèº«ã«ã€ããŠå°ãæžããŠããããŸãã
èšèšæ®µéã§ã¯ãããã€ãã®è³ªåã«çããå¿ èŠããããŸãã
- æ©èœã¹ã¯ãªãããæè»ã«ããã¹ããããç°¡åã«è¿œå ããã³åé€ã§ããããã«ããæ¹æ³ã
- ã¹ããããéãããšãã«ãå¿
èŠãªããŒã¿ããã§ã«å
¥åãããŠããããšã確èªããæ¹æ³ïŒããšãã°ãå
¥ãå£ã®[æè²]ç»é¢ã¯ãæ¢ç¥ã®æè²ã¿ã€ãããã£ãŒã«ãã®æ§æãåæ§ç¯ããã®ãåŸ
ã£ãŠããŸãïŒ
- æçµã¹ãããã®åŸã§ãµãŒããŒã«è»¢éããããã«ããŒã¿ãå
±éã¢ãã«ã«éçŽããæ¹æ³ã
- ã¢ããªã±ãŒã·ã§ã³ãããã©ãããã«ä¿åããŠããŠãŒã¶ãŒãå
¥åãäžæããŠåŸã§æ»ãããšãã§ããããã«ããæ¹æ³ã
ãã®çµæã次ã®æ©èœãååŸããããšèããŠããŸãã
äŸå šäœãGitHubã®ãªããžããªã«ãããŸã
æãããªè§£æ±ºç
ããã«çé»åã¢ãŒããã§æ©èœãéçºããå Žåãæãæçœãªããšã¯ãã¢ããªã±ãŒã·ã§ã³ãªããžã§ã¯ããäœæãããããç»é¢éã§è»¢éããŠãåã¹ãããã§è£å ããããšã§ãã
èãç°è²ã¯ãç¹å®ã®ã¹ãããã§äžèŠãªããŒã¿ã瀺ããŸããåæã«ãæçµçã«æçµçãªã¢ããªã±ãŒã·ã§ã³ã«å ¥ãããã«ããããã¯åç»é¢ã«éä¿¡ãããŸãã
ãã¡ããããã®ãã¹ãŠã®ããŒã¿ã1ã€ã®ã¢ããªã±ãŒã·ã§ã³ãªããžã§ã¯ãã«ããã¯ããå¿ èŠããããŸãããããã©ã®ããã«èŠãããèŠãŠã¿ãŸãããïŒ
class Application(
val name: String?,
val surname: String?,
val educationType : EducationType?,
val workingExperience: Boolean?
val education: Education?,
val experience: Experience?,
val motivation: List<Motivation>?
)
ã ãïŒ
ãã®ãããªãªããžã§ã¯ãã䜿çšããŠãäœåãªäžèŠãªæ°ã®nullãã§ãã¯ã§ã³ãŒããã«ããŒããéåœã«ãããŸããããšãã°ããã®ããŒã¿æ§é ã¯
educationType
ã[æè²]ç»é¢ã§ãã£ãŒã«ãããã§ã«å
¥åãããŠããããšãä¿èšŒãããã®ã§ã¯ãããŸããã
ããè¯ãããæ¹æ³
ããŒã¿ç®¡çãå¥ã®ãªããžã§ã¯ãã«ç§»åããããšããå§ãããŸããããã«ãããåã¹ããããžã®å ¥åã§å¿ èŠãªnulläžå¯èœãªããŒã¿ãæäŸãããåã¹ãããã®çµæããã©ããã«ä¿åãããŸãããã®ãªããžã§ã¯ããã€ã³ã¿ã©ã¯ã¿ãŒãšåŒã³ãŸããããã¯ãRobert Martinã®çŽç²ãªã¢ãŒããã¯ãã£ã®ãŠãŒã¹ã±ãŒã¹ã¬ã€ã€ãŒã«å¯Ÿå¿ãããã¹ãŠã®ç»é¢ã§ãããŸããŸãªãœãŒã¹ïŒãããã¯ãŒã¯ãããŒã¿ããŒã¹ãåã®ã¹ãããã®ããŒã¿ããã©ããææ¡ã®ããŒã¿ãªã©ïŒããåéãããããŒã¿ãæäŸããŸãã
ç§ãã¡ã®ãããžã§ã¯ãã§ã¯ãSurfã§ã¯Daggerã䜿çšããŠããŸããããã€ãã®çç±ãããã€ã³ã¿ã©ã¯ã¿ãŒã¯éåžžãã¹ã³ãŒãã@PerApplicationã«ãªããŸããããã«ãããã€ã³ã¿ã©ã¯ã¿ãŒã¯ã¢ããªã±ãŒã·ã§ã³å ã§ã·ã³ã°ã«ãã³ã«ãªããŸããå®éãã€ã³ã¿ã©ã¯ã¿ãŒã¯ãæ©èœå ã®ã·ã³ã°ã«ãã³ã«ããããšãããã¹ãŠã®ã¹ãããããã©ã°ã¡ã³ãã§ããå Žåã¯ã¢ã¯ãã£ããŒã·ã§ã³ã«ããããšãã§ããŸããããã¯ãã¹ãŠãã¢ããªã±ãŒã·ã§ã³ã®å šäœçãªã¢ãŒããã¯ãã£ã«äŸåããŸãã
ããã«äŸã§ã¯ãã¢ããªã±ãŒã·ã§ã³å šäœã«å¯ŸããŠã€ã³ã¿ã©ã¯ã¿ãŒã®åäžã®ã€ã³ã¹ã¿ã³ã¹ããããšæ³å®ããŸãããããã£ãŠãã¹ã¯ãªããã®çµäºæã«ãã¹ãŠã®ããŒã¿ãã¯ãªã¢ããå¿ èŠããããŸãã
ã¿ã¹ã¯ãèšå®ãããšããäžå åãããããŒã¿ã¹ãã¬ãŒãžã«å ããŠãã¢ããªã±ãŒã·ã§ã³ã®ã¹ãããã®æ§æãšé åºãç°¡åã«ç®¡çã§ããããã«æŽçããããšèããŸããããŠãŒã¶ãŒããã§ã«å ¥åããå 容ã«å¿ããŠãã¹ããããå€æŽã§ããŸãããããã£ãŠããã1ã€ã®ãšã³ãã£ãã£ã§ããã·ããªãªãå¿ èŠã§ãã圌女ã®è²¬ä»»ç¯å²ã¯ããŠãŒã¶ãŒãå®è¡ããå¿ èŠã®ããæé ã®é åºãç¶æããããšã§ãã
ã¹ã¯ãªãããšã€ã³ã¿ã©ã¯ã¿ãŒã䜿çšãã段éçãªæ©èœã®ç·šæã«ããã次ã®ããšãå¯èœã«ãªããŸãã
- ã¹ã¯ãªããã®ã¹ããããå€æŽããã®ã¯ç°¡åã§ããããšãã°ãå®è¡äžã«ãŠãŒã¶ãŒããªã¯ãšã¹ããéä¿¡ããããããã«æ
å ±ãå¿
èŠãªå Žåã«ã¹ããããè¿œå ãããã§ããªãããšãå€æããå Žåãããã«äœæ¥ãéããããšãã§ããŸãã
- å¥çŽã®èšå®ïŒåã¹ãããã®å
¥åãšåºåã«å¿
èŠãªããŒã¿ã
- ãŠãŒã¶ãŒããã¹ãŠã®ç»é¢ãå®äºããŠããªãå Žåã¯ãã¢ããªã±ãŒã·ã§ã³ããã©ããã«ä¿åããããã«æŽçããŸãã
äžæžãã§ä¿åãããããŒã¿ãç»é¢ã«äºåå ¥åããŸãã
åºæ¬ãšã³ãã£ãã£
ãã®æ©èœã®ã¡ã«ããºã ã¯æ¬¡ã®ãšããã§ãã
- ã¹ããããå
¥åãããã³åºåãèšè¿°ããããã®ã¢ãã«ã®ã»ããã
- ã·ããªãª-ãŠãŒã¶ãŒãå®è¡ããå¿
èŠã®ããã¹ãããïŒç»é¢ïŒã説æãããšã³ãã£ãã£ã
- InteractorïŒProgressInteractorïŒ-çŸåšã¢ã¯ãã£ããªã¹ãããã«é¢ããæ
å ±ãä¿åããåã¹ãããã®å®äºåŸã«å
¥åãããæ
å ±ãéçŽããæ°ããã¹ããããéå§ããããã®å
¥åããŒã¿ãçºè¡ããã¯ã©ã¹ã
- DraftïŒApplicationDraftïŒ-å
¥åãããæ
å ±ã®ä¿åãæ
åœããã¯ã©ã¹ã
ã¯ã©ã¹å³ã¯ãå ·äœçãªå®è£ ãç¶æ¿ãããã¹ãŠã®åºç€ãšãªããšã³ãã£ãã£ãè¡šããŸããããããã©ã®ããã«é¢é£ããŠãããèŠãŠã¿ãŸãããã
ã·ããªãªãšã³ãã£ãã£ã®å Žåãã¢ããªã±ãŒã·ã§ã³ã®ã·ããªãªã«æåŸ ãããããžãã¯ã説æããã€ã³ã¿ãŒãã§ã€ã¹ãèšå®ããŸãïŒå¿ èŠãªæé ã®ãªã¹ããå«ã¿ãå¿ èŠã«å¿ããŠåã®æé ãå®äºããåŸã«åæ§ç¯ããŸãã
ã¢ããªã±ãŒã·ã§ã³ã«ã¯ãå€æ°ã®é£ç¶ããç»é¢ã§æ§æãããè€æ°ã®æ©èœãããããããããæ©èœãç¹å®ã®ããŒã¿ã«äŸåããªããã¹ãŠã®äžè¬çãªããžãã¯ãåºæ¬ã¯ã©ã¹ProgressInteractorã«ç§»åããŸãã
ãŠãŒã¶ãŒãå ¥åããããŒã¿ããã©ããã«ä¿åããå¿ èŠããªãå ŽåããããããApplicationDraftã¯åºæ¬ã¯ã©ã¹ã«ååšããŸããããããã£ãŠãProgressInteractorã®å ·äœçãªå®è£ ã¯ãã©ããã§æ©èœããŸããã¹ã¯ãªãŒã³ãã¬ãŒã³ã¿ãŒããããšå¯Ÿè©±ããŸãã
åºæ¬ã¯ã©ã¹ã®ç¹å®ã®å®è£ ã®ã¯ã©ã¹å³ïŒ
ãããã®ãšã³ãã£ãã£ã¯ãã¹ãŠã次ã®ããã«çžäºã«ãããã³ç»é¢ãã¬ãŒã³ã¿ãŒãšçžäºäœçšããŸãã
ã¯ã©ã¹ã¯ããªãå€ãã®ã§ãèšäºã®æåããæ©èœã䜿çšããŠåãããã¯ãåå¥ã«åæããŸãããã
æé ã®èª¬æ
æåã®ãã€ã³ãããå§ããŸããããæé ã説æãããšã³ãã£ãã£ãå¿ èŠã§ãã
// , ,
interface Step
ãžã§ãã¢ããªã±ãŒã·ã§ã³ã®äŸã®æ©èœã®å Žåãæé ã¯æ¬¡ã®ãšããã§ãã
/**
*
*/
enum class ApplicationSteps : Step {
PERSONAL_INFO, //
EDUCATION, //
EXPERIENCE, //
ABOUT_ME, // " "
MOTIVATION //
}
ãŸããåã¹ãããã®å ¥åããŒã¿ãèšè¿°ããå¿ èŠããããŸãããããè¡ãããã«ãæå³ãããç®çã®ããã«å°å°ãããã¯ã©ã¹ã䜿çšããŸã-éå®ãããã¯ã©ã¹éå±€ãäœæããŸãã
ã³ãŒãã§ã©ã®ããã«èŠããã
:
//
interface StepInData
:
//,
sealed class ApplicationStepInData : StepInData
//
class EducationStepInData(val educationType: EducationType) : ApplicationStepInData()
//
class MotivationStepInData(val values: List<Motivation>) : ApplicationStepInData()
åæ§ã®æ¹æ³ã§åºåã説æããŸãã
ã³ãŒãã§ã©ã®ããã«èŠããã
// ,
interface StepOutData
//,
sealed class ApplicationStepOutData : StepOutData
// " "
class PersonalInfoStepOutData(
val info: PersonalInfo
) : ApplicationStepOutData()
// ""
class EducationStepOutData(
val education: Education
) : ApplicationStepOutData()
// " "
class ExperienceStepOutData(
val experience: WorkingExperience
) : ApplicationStepOutData()
// " "
class AboutMeStepOutData(
val info: AboutMe
) : ApplicationStepOutData()
// " "
class MotivationStepOutData(
val motivation: List<Motivation>
) : ApplicationStepOutData()
æªèšå ¥ã®ã¢ããªã±ãŒã·ã§ã³ããã©ããã«ä¿æãããšããç®æšãèšå®ããªãã£ãå Žåã¯ãããã«éå®ããããšãã§ããŸãããã ããåç»é¢ã¯ç©ºã§éãã ãã§ãªããäžæžãããå ¥åããããšãã§ããããããŠãŒã¶ãŒããã§ã«äœããå ¥åããŠããå Žåã¯ãå ¥åããŒã¿ãšäžæžãããã®ããŒã¿ã®äž¡æ¹ãã€ã³ã¿ã©ã¯ã¿ãŒããã®å ¥åã«éãããŸãã
ãããã£ãŠããã®ããŒã¿ããŸãšããã«ã¯ãå¥ã®ã¢ãã«ã®ã»ãããå¿ èŠã§ããäžéšã®æé ã§ã¯ãå ¥åããããã®æ å ±ãå¿ èŠãšããããã©ããããã®ããŒã¿ã®ãã£ãŒã«ãã®ã¿ãæäŸããŸã
ã³ãŒãã§ã©ã®ããã«èŠããã
/**
* + ,
*/
interface StepData<I : StepInData, O : StepOutData>
sealed class ApplicationStepData : StepData<ApplicationStepInData, ApplicationStepOutData> {
class PersonalInfoStepData(
val outData: PersonalInfoStepOutData?
) : ApplicationStepData()
class EducationStepData(
val inData: EducationStepInData,
val outData: EducationStepOutData?
) : ApplicationStepData()
class ExperienceStepData(
val outData: ExperienceStepOutData?
) : ApplicationStepData()
class AboutMeStepData(
val outData: AboutMeStepOutData?
) : ApplicationStepData()
class MotivationStepData(
val inData: MotivationStepInData,
val outData: MotivationStepOutData?
) : ApplicationStepData()
}
ã¹ã¯ãªããã«åŸã£ãŠè¡åããŸã
æé ã®èª¬æãšå ¥å/åºåããŒã¿ãæŽçãããŠããŸãã次ã«ãã³ãŒãã®æ©èœã¹ã¯ãªããã§ãããã®æé ã®é åºãä¿®æ£ããŸããããã·ããªãªãšã³ãã£ãã£ã¯ãçŸåšã®ã¹ãããã®é åºã管çãã責任ããããŸããã¹ã¯ãªããã¯æ¬¡ã®ããã«ãªããŸãã
/**
* , ,
*/
interface Scenario<S : Step, O : StepOutData> {
//
val steps: List<S>
/**
*
*
*/
fun reactOnStepCompletion(stepOut: O)
}
ãã®äŸã®å®è£ ã§ã¯ãã¹ã¯ãªããã¯æ¬¡ã®ããã«ãªããŸãã
class ApplicationScenario : Scenario<ApplicationStep, ApplicationStepOutData> {
override val steps: MutableList<ApplicationStep> = mutableListOf(
PERSONAL_INFO,
EDUCATION,
EXPERIENCE,
MOTIVATION
)
override fun reactOnStepCompletion(stepOut: ApplicationStepOutData) {
when (stepOut) {
is PersonalInfoStepOutData -> {
changeScenarioAfterPersonalStep(stepOut.info)
}
}
}
private fun changeScenarioAfterPersonalStep(personalInfo: PersonalInfo) {
applyExperienceToScenario(personalInfo.hasWorkingExperience)
applyEducationToScenario(personalInfo.education)
}
/**
* -
*/
private fun applyEducationToScenario(education: EducationType) {...}
/**
* ,
*
*/
private fun applyExperienceToScenario(hasWorkingExperience: Boolean) {...}
}
ã¹ã¯ãªããã®å€æŽã¯åæ¹åã§ããå¿ èŠãããããšã«æ³šæããŠãã ãããã¹ããããåé€ãããšããŸãããŠãŒã¶ãŒãæ»ã£ãŠå¥ã®ãªãã·ã§ã³ãéžæããå Žåã¯ãã¹ããããã¹ã¯ãªããã«è¿œå ãããŠããããšã確èªããŠãã ããã
ããšãã°ãã³ãŒãã¯äœæ¥çµéšã®æç¡ã«å¯Ÿããåå¿ã®ããã«èŠããŸãã
/**
* ,
*
*/
private fun applyExperienceToScenario(hasWorkingExperience: Boolean) {
if (hasWorkingExperience) {
steps.replaceWith(
condition = { it == ABOUT_ME },
newElem = EXPERIENCE
)
} else {
steps.replaceWith(
condition = { it == EXPERIENCE },
newElem = ABOUT_ME
)
}
}
Interactorã®ããã¿
ã¹ããããã€ã¹ãããæ©èœã®ã¢ãŒããã¯ãã£ã®æ¬¡ã®æ§æèŠçŽ ã§ããã€ã³ã¿ã©ã¯ã¿ãŒã«ã€ããŠèããŠã¿ãŸããäžã§è¿°ã¹ãããã«ããã®äž»ãªè²¬ä»»ã¯ãã¹ãããéã®åãæ¿ããåŠçããããšã§ããã¹ããããžã®å ¥åã«å¿ èŠãªããŒã¿ãæäŸããåºåããŒã¿ããã©ããèŠæ±ã«éçŽããŸãã
ã€ã³ã¿ã©ã¯ã¿ãŒã®åºæ¬ã¯ã©ã¹ãäœæãããã¹ãŠã®ã¹ããããã€ã¹ãããæ©èœã«å ±éã®åäœããã®äžã«å ¥ããŸãããã
/**
*
* S -
* I -
* O -
*/
abstract class ProgressInteractor<S : Step, I : StepInData, O : StepOutData>
ã€ã³ã¿ã©ã¯ã¿ãŒã¯çŸåšã®ã·ããªãªã§äœæ¥ããå¿ èŠããããŸããã·ããªãªãäžé£ã®ã¹ããããåæ§ç¯ã§ããããã«ã次ã®ã¹ãããã®å®äºã«ã€ããŠã€ã³ã¿ã©ã¯ã¿ãŒã«éç¥ããŸãããããã£ãŠãã¹ã¯ãªããã®æœè±¡ãã£ãŒã«ãã宣èšããŸããããã§ãç¹å®ã®ã€ã³ã¿ã©ã¯ã¿ãŒããšã«ç¬èªã®å®è£ ãæäŸããå¿ èŠããããŸãã
// ,
protected abstract val scenario: Scenario<S, O>
ã€ã³ã¿ã©ã¯ã¿ãŒã¯ãçŸåšã¢ã¯ãã£ããªã¹ãããã®ç¶æ ãä¿åãã次ãŸãã¯åã®ã¹ãããã«åãæ¿ãã圹å²ãæãããŸããç®çã®ãã©ã°ã¡ã³ãã«åãæ¿ããããšãã§ããããã«ãã¹ãããã®å€æŽãã«ãŒãç»é¢ã«è¿ éã«éç¥ããå¿ èŠããããŸããããã¯ãã¹ãŠãã€ãã³ããããŒããã£ã¹ããã€ãŸããªã¢ã¯ãã£ãã¢ãããŒãã䜿çšããŠç°¡åã«æŽçã§ããŸãããŸããã€ã³ã¿ã©ã¯ã¿ãŒã®ã¡ãœããã¯éåææäœïŒãããã¯ãŒã¯ãŸãã¯ããŒã¿ããŒã¹ããã®ããŒã¿ã®ããŒãïŒãå®è¡ããããšãå€ããããRxJavaã䜿çšããŠã€ã³ã¿ã©ã¯ã¿ãŒãšãã¬ãŒã³ã¿ãŒãšéä¿¡ããŸãããã®ããŒã«ã«ãŸã æ £ããŠããªãå Žåã¯ããã®äžé£ã®çŽ¹ä»èšäºããèªã¿ãã ããã
çŸåšã®ã¹ããããšã¹ã¯ãªããå ã®ãã®äœçœ®ã«ã€ããŠç»é¢ã«å¿ èŠãªæ å ±ã説æããã¢ãã«ãäœæããŸãããã
/**
*
*/
class StepWithPosition<S : Step>(
val step: S,
val position: Int,
val allStepsCount: Int
)
ã€ã³ã¿ã©ã¯ã¿ãŒã§BehaviorSubjectãéå§ããŠãæ°ããã¢ã¯ãã£ããªã¹ãããã«é¢ããæ å ±ãèªç±ã«åºåããŠã¿ãŸãããã
private val stepChangeSubject = BehaviorSubject.create<StepWithPosition<S>>()
ç»é¢ããã®ã€ãã³ãã®ã¹ããªãŒã ããµãã¹ã¯ã©ã€ãã§ããããã«ãstepChangeSubjectã®ã©ãããŒã§ãããããªãã¯å€æ°stepChangeObservableãäœæããŸãã
val stepChangeObservable: Observable<StepWithPosition<S>> = stepChangeSubject.hide()
ã€ã³ã¿ã©ã¯ã¿ãŒã®äœæ¥äžã«ãçŸåšã¢ã¯ãã£ããªã¹ãããã®äœçœ®ãç¥ãå¿ èŠãããããšããããããŸããã€ã³ã¿ã©ã¯ã¿ãŒã«å¥ã®ããããã£ïŒcurrentStepIndexïŒãäœæããgetïŒïŒã¡ãœãããšsetïŒïŒã¡ãœããããªãŒããŒã©ã€ãããããšããå§ãããŸããããã«ããã件åãããã®æ å ±ã«ç°¡åã«ã¢ã¯ã»ã¹ã§ããŸãã
ã³ãŒãã§ã©ã®ããã«èŠããã
//
private var currentStepIndex: Int
get() = stepChangeSubject.value?.position ?: 0
set(value) {
stepChangeSubject.onNext(
StepWithPosition(
step = scenario.steps[value],
position = value,
allStepsCount = scenario.steps.count()
)
)
}
æ©èœã®ã€ã³ã¿ã©ã¯ã¿ãŒã®ç¹å®ã®å®è£ ã«é¢ä¿ãªããåãããã«æ©èœããäžè¬çãªéšåãæžããŠã¿ãŸãããã
ã€ã³ã¿ã©ã¯ã¿ãŒãåæåããã³ã·ã£ããããŠã³ããŠãåå«ã§æ¡åŒµã§ããããã«ããããã®ã¡ãœãããè¿œå ããŸãããã
åæåãšã·ã£ããããŠã³ã®æ¹æ³
/**
*
*/
@CallSuper
open fun initProgressFeature() {
currentStepIndex = 0
}
/**
*
*/
@CallSuper
open fun closeProgressFeature() {
currentStepIndex = 0
}
ã¹ããããã€ã¹ãããã®æ©èœã€ã³ã¿ã©ã¯ã¿ãŒãå®è¡ããå¿ èŠã®ããæ©èœãè¿œå ããŸãããã
- getDataForStepïŒã¹ãããïŒSïŒ-ã¹ãããSãžã®å
¥åãšããŠããŒã¿ãæäŸããŸãã
- completeStepïŒstepOutïŒOïŒ-Oåºåãä¿åããã¹ã¯ãªããã次ã®ã¹ãããã«ç§»åããŸãã
- toPreviousStepïŒïŒ-ã¹ã¯ãªãããåã®ã¹ãããã«ç§»åããŸãã
æåã®é¢æ°ã§ããå ¥åããŒã¿ã®åŠçããå§ããŸããããåã€ã³ã¿ã©ã¯ã¿ãŒèªäœããå ¥åããŒã¿ãååŸããæ¹æ³ãšå Žæã決å®ããŸãããããæ åœããæœè±¡çãªã¡ãœãããè¿œå ããŸãããïŒ
/**
*
*/
protected abstract fun resolveStepInData(step: S): Single<out StepData<I, O>>
ç¹å®ã®ç»é¢ã®ãã¬ãŒã³ã¿ãŒã®å ŽåããåŒã³åºããããªãã¯ã¡ãœãããè¿œå ããŸã
resolveStepInData() :
/**
*
*/
fun getDataForStep(step: S): Single<out StepData<I, O>> = resolveStepInData(step)
ã¡ãœãããpublicã«ããããšã§ããã®ã³ãŒããåçŽåã§ã
resolveStepInData()
ãŸãããã®æ¹æ³ã¯getDataForStep()
ã以äžã§èª¬æããã¹ãããå®äºæ¹æ³ãšã®é¡äŒŒæ§ã®ããã«è¿œå ãããŠããŸãã
ã¹ããããå®äºããããã«ãåæ§ã«ãç¹å®ã®åã€ã³ã¿ã©ã¯ã¿ãŒãã¹ãããã®çµæãä¿åããæœè±¡çãªã¡ãœãããäœæããŸãã
/**
*
*/
protected abstract fun saveStepOutData(stepData: O): Completable
ãããŠå ¬çãªæ¹æ³ããã®äžã§ãåºåæ å ±ã®ä¿åãšåŒã³ãŸããçµäºããããçµäºã¹ãããããã®æ å ±ã«èª¿æŽããããã«ã¹ã¯ãªããã«æ瀺ããŸãããŸããäžæ©åé²ããŠããããšããµãã¹ã¯ã©ã€ããŒã«éç¥ããŸãã
/**
*
*/
fun completeStep(stepOut: O): Completable {
return saveStepOutData(stepOut).doOnComplete {
scenario.reactOnStepCompletion(stepOut)
if (currentStepIndex != scenario.steps.lastIndex) {
currentStepIndex += 1
}
}
}
æåŸã«ãåã®ã¹ãããã«æ»ãã¡ãœãããå®è£ ããŸãã
/**
*
*/
fun toPreviousStep() {
if (currentStepIndex != 0) {
currentStepIndex -= 1
}
}
ãžã§ãã¢ããªã±ãŒã·ã§ã³ã®äŸã®ã€ã³ã¿ã©ã¯ã¿ãŒã®å®è£ ãèŠãŠã¿ãŸããããèŠããŠããããã«ããã®æ©èœã§ã¯ãã©ãããªã¯ãšã¹ãã«ããŒã¿ãä¿åããããšãéèŠã§ãããããã£ãŠãApplicationProgressInteractorã¯ã©ã¹ã§ããã©ããã®äžã«è¿œå ã®ãã£ãŒã«ããäœæããŸãã
/**
*
*/
@PerApplication
class ApplicationProgressInteractor @Inject constructor(
private val dataRepository: ApplicationDataRepository
) : ProgressInteractor<ApplicationSteps, ApplicationStepInData, ApplicationStepOutData>() {
//
override val scenario = ApplicationScenario()
//
private val draft: ApplicationDraft = ApplicationDraft()
//
fun applyDraft(draft: ApplicationDraft) {
this.draft.apply {
clear()
outDataMap.putAll(draft.outDataMap)
}
}
...
}
ãã©ããã¯ã©ã¹ã¯ã©ã®ããã«èŠããã
:
/**
*
*/
class ApplicationDraft(
val outDataMap: MutableMap<ApplicationSteps, ApplicationStepOutData> = mutableMapOf()
) : Serializable {
fun getPersonalInfoOutData() = outDataMap[PERSONAL_INFO] as? PersonalInfoStepOutData
fun getEducationStepOutData() = outDataMap[EDUCATION] as? EducationStepOutData
fun getExperienceStepOutData() = outDataMap[EXPERIENCE] as? ExperienceStepOutData
fun getAboutMeStepOutData() = outDataMap[ABOUT_ME] as? AboutMeStepOutData
fun getMotivationStepOutData() = outDataMap[MOTIVATION] as? MotivationStepOutData
fun clear() {
outDataMap.clear()
}
}
芪ã¯ã©ã¹ã§å®£èšãããæœè±¡ã¡ãœããã®å®è£ ãå§ããŸããããã¹ãããå®äºæ©èœããå§ããŸããã-ããã¯éåžžã«ç°¡åã§ããç¹å®ã®ã¿ã€ãã®åºåãç®çã®ããŒã®äžã®ãã©ããã«ä¿åããŸãã
/**
*
*/
override fun saveStepOutData(stepData: ApplicationStepOutData): Completable {
return Completable.fromAction {
when (stepData) {
is PersonalInfoStepOutData -> {
draft.outDataMap[PERSONAL_INFO] = stepData
}
is EducationStepOutData -> {
draft.outDataMap[EDUCATION] = stepData
}
is ExperienceStepOutData -> {
draft.outDataMap[EXPERIENCE] = stepData
}
is AboutMeStepOutData -> {
draft.outDataMap[ABOUT_ME] = stepData
}
is MotivationStepOutData -> {
draft.outDataMap[MOTIVATION] = stepData
}
}
}
}
次ã«ãã¹ãããã®å ¥åããŒã¿ãååŸããæ¹æ³ãèŠãŠã¿ãŸãããã
/**
*
*/
override fun resolveStepInData(step: ApplicationStep): Single<ApplicationStepData> {
return when (step) {
PERSONAL_INFO -> ...
EXPERIENCE -> ...
EDUCATION -> Single.just(
EducationStepData(
inData = EducationStepInData(
draft.getPersonalInfoOutData()?.info?.educationType
?: error("Not enough data for EDUCATION step")
),
outData = draft.getEducationStepOutData()
)
)
ABOUT_ME -> Single.just(
AboutMeStepData(
outData = draft.getAboutMeStepOutData()
)
)
MOTIVATION -> dataRepository.loadMotivationVariants().map { reasonsList ->
MotivationStepData(
inData = MotivationStepInData(reasonsList),
outData = draft.getMotivationStepOutData()
)
}
}
}
ã¹ããããéããšãã2ã€ã®ãªãã·ã§ã³ããããŸãïŒ
- ãŠãŒã¶ãŒãåããŠç»é¢ãéããŸãã
- ãŠãŒã¶ãŒã¯ãã§ã«ç»é¢ã«å
¥åããŠãããäžæžãã«ããŒã¿ãä¿åããŠããŸãã
äœãå ¥åããå¿ èŠã®ãªãã¹ãããã«ã€ããŠã¯ããã©ããããã®æ å ±ïŒããå ŽåïŒãæž¡ããŸãã
ABOUT_ME -> Single.just(
AboutMeStepData(
stepOutData = draft.getAboutMeStepOutData()
)
)
åã®ã¹ãããã®ããŒã¿ãå ¥åãšããŠå¿ èŠãªå Žåã¯ããã©ããããåŒãåºããŸãïŒåã¹ãããã®æåŸã«å¿ ãä¿åããŸãïŒãåæ§ã«ãç»é¢å šäœã«äœ¿çšã§ããoutDataã«ããŒã¿ã転éããŸãã
EDUCATION -> Single.just(
EducationStepData(
inData = EducationStepInData(
draft.getPersonalInfoOutData()?.info?.educationType
?: error("Not enough data for EDUCATION step")
),
outData = draft.getEducationStepOutData()
)
)
ããã«èå³æ·±ãç¶æ³ããããŸãããŠãŒã¶ãŒããã®ç¹å®ã®æ¬ å¡ã«é¢å¿ãæã£ãŠããçç±ã瀺ãå¿ èŠãããæåŸã®ã¹ãããã§ã¯ãèããããçç±ã®ãªã¹ãããããã¯ãŒã¯ããããŠã³ããŒãããå¿ èŠããããŸããããã¯ããã®ã¢ãŒããã¯ãã£ã§æã䟿å©ãªç¬éã®1ã€ã§ãããªã¯ãšã¹ããéä¿¡ããåçãåãåã£ããããã©ããã®ããŒã¿ãšçµã¿åãããŠãå ¥åãšããŠç»é¢ã«éä¿¡ã§ããŸããç»é¢ã¯ãããŒã¿ã®åºæãåéããŠãããœãŒã¹ã®æ°ãç¥ãå¿ èŠãããããŸããã
MOTIVATION -> {
dataRepository.loadMotivationVariants().map { reasonsList ->
MotivationStepData(
inData = MotivationStepInData(reasonsList),
outData = draft.getMotivationStepOutData()
)
}
}
ãã®ãããªç¶æ³ã¯ãã€ã³ã¿ã©ã¯ã¿ãŒãä»ããŠäœæ¥ããããšãæ¯æããå¥ã®è°è«ã§ããã¹ãããã«ããŒã¿ãæäŸããããã«ãWebããã®ããŠã³ããŒããåã®ã¹ãããã®çµæãªã©ãããã€ãã®ããŒã¿ãœãŒã¹ãçµã¿åãããå¿ èŠãããå ŽåããããŸãã
ç§ãã¡ã®æ¹æ³ã§ã¯ãå€ãã®ãœãŒã¹ããã®ããŒã¿ãçµã¿åãããŠãå¿ èŠãªãã®ãã¹ãŠãç»é¢ã«æäŸã§ããŸãããã®äŸã§ãããåªããŠããçç±ãç解ããã®ã¯é£ãããããããŸãããå®éã®åœ¢åŒã§ã¯ïŒããšãã°ãããŒã³ãç³è«ããå ŽåïŒãç»é¢ã«ã¯ãå€ãã®ãªãã¡ã¬ã³ã¹ããã¯ãå éšããŒã¿ããŒã¹ããã®ãŠãŒã¶ãŒã«é¢ããæ å ±ã5ã¹ãããåã«å ¥åããããŒã¿ãããã³1970幎ããã®æã人æ°ã®ããéžè©±ã®ã³ã¬ã¯ã·ã§ã³ãéä¿¡ããå¿ èŠããããŸãã
ãã¬ãŒã³ã¿ãŒã³ãŒãã¯ãçµæïŒããŒã¿ãŸãã¯ãšã©ãŒïŒã®ã¿ãçæããå¥ã®ã€ã³ã¿ã©ã¯ã¿ãŒã¡ãœããã«ãã£ãŠéèšãè¡ãããå Žåãã¯ããã«ç°¡åã«ãªããŸãããã¹ãŠãæ¢ãå Žæãããã«æ確ã«ãªãã°ãéçºè ã¯å€æŽã調æŽãè¡ãã®ãç°¡åã«ãªããŸãã
ããããã€ã³ã¿ã©ã¯ã¿ãŒã«ããã®ã¯ããã ãã§ã¯ãããŸããããã¡ããããã¹ãŠã®ã¹ããããå®äºãããšãã«ãæçµçãªã¢ããªã±ãŒã·ã§ã³ãéä¿¡ããã¡ãœãããå¿ èŠã§ããæçµçãªã¢ããªã±ãŒã·ã§ã³ãšãããã«ããŒããã¿ãŒã³ã䜿çšããŠãããäœæããæ©èœã«ã€ããŠèª¬æããŸãããã
æçµç³è«æžæåºã¯ã©ã¹
/**
*
*/
class Application(
val personal: PersonalInfo,
val education: Education?,
val experience: Experience,
val motivation: List<Motivation>
) {
class Builder {
private var personal: Optional<PersonalInfo> = Optional.empty()
private var education: Optional<Education?> = Optional.empty()
private var experience: Optional<Experience> = Optional.empty()
private var motivation: Optional<List<Motivation>> = Optional.empty()
fun personalInfo(value: PersonalInfo) = apply { personal = Optional.of(value) }
fun education(value: Education) = apply { education = Optional.of(value) }
fun experience(value: Experience) = apply { experience = Optional.of(value) }
fun motivation(value: List<Motivation>) = apply { motivation = Optional.of(value) }
fun build(): Application {
return try {
Application(
personal.get(),
education.getOrNull(),
experience.get(),
motivation.get()
)
} catch (e: NoSuchElementException) {
throw ApplicationIsNotFilledException(
"""Some fields aren't filled in application
personal = {${personal.getOrNull()}}
experience = {${experience.getOrNull()}}
motivation = {${motivation.getOrNull()}}
""".trimMargin()
)
}
}
}
}
ã¢ããªã±ãŒã·ã§ã³èªäœãéä¿¡ããæ¹æ³ïŒ
/**
*
*/
fun sendApplication(): Completable {
val builder = Application.Builder().apply {
draft.outDataMap.values.forEach { data ->
when (data) {
is PersonalInfoStepOutData -> personalInfo(data.info)
is EducationStepOutData -> education(data.education)
is ExperienceStepOutData -> experience(data.experience)
is AboutMeStepOutData -> experience(data.info)
is MotivationStepOutData -> motivation(data.motivation)
}
}
}
return dataRepository.loadApplication(builder.build())
}
ç»é¢äžã§ãã¹ãŠã䜿çšããæ¹æ³
ããã§ããã¬ãŒã³ããŒã·ã§ã³ã¬ãã«ã«ç§»åããŠãã¹ã¯ãªãŒã³ãã¬ãŒã³ã¿ãŒããã®ã€ã³ã¿ã©ã¯ã¿ãŒãšã©ã®ããã«å¯Ÿè©±ãããã確èªãã䟡å€ããããŸãã
ç§ãã¡ã®æ©èœã¯ããã©ã°ã¡ã³ãã®ã¹ã¿ãã¯ãå éšã«æã€ã¢ã¯ãã£ããã£ã§ãã
ã¢ããªã±ãŒã·ã§ã³ã®éä¿¡ãæåãããšãå¥ã®ã¢ã¯ãã£ããã£ãéããéä¿¡ã®æåã«ã€ããŠãŠãŒã¶ãŒã«éç¥ãããŸããã¡ã€ã³ã¢ã¯ãã£ããã£ã¯ãã€ã³ã¿ã©ã¯ã¿ãŒã®ã³ãã³ãã«å¿ããŠãç®çã®ãã©ã°ã¡ã³ãã衚瀺ããããŒã«ããŒã§ãã§ã«å®è¡ãããã¹ãããæ°ã衚瀺ãã圹å²ãæãããŸãããããè¡ãã«ã¯ãã«ãŒãã¢ã¯ãã£ããã£ãã¬ãŒã³ã¿ãŒã§ãã€ã³ã¿ã©ã¯ã¿ãŒãããµããžã§ã¯ãããµãã¹ã¯ã©ã€ãããã¹ã¿ãã¯å ã®ãã©ã°ã¡ã³ããåãæ¿ããããã®ããžãã¯ãå®è£ ããŸãã
progressInteractor.stepChangeObservable.subscribe { stepData ->
if (stepData.position > currentPosition) {
// FragmentManager
} else {
//
}
// -
}
åãã©ã°ã¡ã³ãã®ãã¬ãŒã³ã¿ãŒã§ãç»é¢ã®éå§æã«ãã€ã³ã¿ã©ã¯ã¿ãŒã«å ¥åããŒã¿ãæäŸããããã«äŸé ŒããŸããåè¿°ã®ããã«ãåä¿¡ããŒã¿ã¯ãããã¯ãŒã¯ããã®ããŠã³ããŒãã«é¢é£ä»ããããšãã§ãããããåä¿¡ããŒã¿ãå¥ã®ã¹ããªãŒã ã«è»¢éããããšããå§ãããŸãã
ããšãã°ãæè²æ å ±ãå ¥åããããã®ç»é¢ãèŠãŠã¿ãŸãããã
progressInteractor.getDataForStep(EducationStep)
.filter<ApplicationStepData.EducationStepData>()
.subscribeOn(Schedulers.io())
.subscribe {
val educationType = it.stepInData.educationType
// todo:
it.stepOutData?.education?.let {
// todo:
}
}
ãæè²ã«ã€ããŠãã®ã¹ããããå®äºãããŠãŒã¶ãŒãããã«é²ãã§ãããããšããŸããåºåã䜿çšããŠãªããžã§ã¯ãã圢æãããããã€ã³ã¿ã©ã¯ã¿ãŒã«æž¡ãã ãã§ãã
progressInteractor.completeStep(EducationStepOutData(education)).subscribe {
// ( )
}
ã€ã³ã¿ã©ã¯ã¿ãŒã¯ããŒã¿èªäœãä¿åããå¿ èŠã«å¿ããŠã¹ã¯ãªããã®å€æŽãéå§ããã«ãŒãã¢ã¯ãã£ããã£ã«æ¬¡ã®ã¹ãããã«åãæ¿ããããã«éç¥ããŸãããããã£ãŠããã©ã°ã¡ã³ãã¯ã¹ã¯ãªããå ã§ã®äœçœ®ã«ã€ããŠäœãç¥ããŸãããããšãã°ãæ©èœã®èšèšãå€æŽãããå Žåããã©ã°ã¡ã³ãã¯ç°¡åã«åé 眮ã§ããŸãã
æåŸã®ãã©ã°ã¡ã³ãã§ã¯ãããŒã¿ã®ä¿åãæåããããšãžã®åå¿ãšããŠãæåŸã®ãªã¯ãšã¹ãã®éä¿¡ãè¿œå ããŸããèŠããŠãããã
sendApplication()
ã«ãã€ã³ã¿ã©ã¯ã¿ãŒã§ãã®ããã®ã¡ãœãããäœæããŸããã
progressInteractor.sendApplication()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
//
activityNavigator.start(ThankYouRoute())
},
{
//
}
)
ã¢ããªã±ãŒã·ã§ã³ãæ£åžžã«éä¿¡ããããšããæ å ±ã衚瀺ãããæåŸã®ç»é¢ã§ãã€ã³ã¿ã©ã¯ã¿ãŒãã¯ãªã¢ããŠãããã»ã¹ãæåããåéã§ããããã«ããŸãã
progressInteractor.closeProgressFeature()
ããã§å šéšã§ãã5ã€ã®ç»é¢ã§æ§æãããæ©èœããããŸãããæè²ã«ã€ããŠãã®ç»é¢ã¯ã¹ãããã§ããä»äºã®çµéšãèšå ¥ããç»é¢ã¯ããšãã»ã€ãæžãããã®ç»é¢ã«çœ®ãæããããŸããä»»æã®ã¹ãããã§å ¥åãäžæããŠåŸã§ç¶è¡ã§ããå ¥åãããã®ã¯ãã¹ãŠãã©ããã«ä¿åãããŸãããããžã§ã¯ãã§ãã®ã¢ãããŒããæåã«å®è£ ããèè ã§ãã
VasyaBeglyanin @ icebailã«ç¹ã«æè¬ããŸãããŸããMisha Zinchenko @ midery-ãã©ããã¢ãŒããã¯ãã£ãæçµããŒãžã§ã³ã«ããããã®ãã«ãïŒãã®èšäºã§èª¬æïŒã