Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
SUGARのアーキテクチャー / SUGAR ARCHITECTURE 20190425
Search
sugitani
April 25, 2019
Technology
2
1.8k
SUGARのアーキテクチャー / SUGAR ARCHITECTURE 20190425
2019/4/25に行われた「突撃!!隣のアーキテクチャ」
https://totsugeki-architecture.connpass.com/event/125845/
での発表資料です
sugitani
April 25, 2019
Tweet
Share
Other Decks in Technology
See All in Technology
レガシーをぶっ壊せ。AEONで始めるDevRelの話 / Qiita Night 2024-2-22
aeonpeople
3
1.3k
TechFeed Experts Night#27 〜 フロントエンドフレームワーク最前線 (Svelte)
baseballyama
1
520
自己改善からチームを動かす! 「セルフエンジニアリングマネージャー」のすゝめ
shoota
6
720
いつか使うかも貯金してたらめちゃめちゃ機能が増えてた話
riyaamemiya
0
150
Meta Quest 3 で動く桜マシマシ WebXR アプリを IBM Cloud Code Engine と Babylon.js で作った話
1ftseabass
PRO
0
120
Delivering Millions of Messages within seconds @ Duolingo
pelelgrino
0
350
ゼロから始めるVue.jsコミュニティ貢献 / first-vuejs-community-contribution-link-and-motivation
lmi
1
130
AWSに詳しくない人でも始められるコスト最適化ガイド
yuhta28
1
240
エンジニアのキャリアをちょっと楽しくする3本の軸/Three Pillars to Make an Engineer's Career More Enjoyable
kwappa
0
2.7k
Gitlab本から学んだこと - そーだいなるプレイバック / gitlab-book
soudai
4
430
MLOpsの「壁」を乗り越える、LINEヤフーの Data Quality as Code
lycorptech_jp
PRO
5
530
JSON攻略法.pdf
miyakemito
8
5k
Featured
See All Featured
We Have a Design System, Now What?
morganepeng
43
6.8k
Teambox: Starting and Learning
jrom
128
8.4k
ParisWeb 2013: Learning to Love: Crash Course in Emotional UX Design
dotmariusz
104
6.6k
Scaling GitHub
holman
457
140k
Robots, Beer and Maslow
schacon
PRO
155
7.9k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
78
42k
Building Applications with DynamoDB
mza
88
5.6k
Automating Front-end Workflow
addyosmani
1356
200k
BBQ
matthewcrist
80
8.8k
jQuery: Nuts, Bolts and Bling
dougneiner
59
7.1k
The Mythical Team-Month
searls
216
42k
Documentation Writing (for coders)
carmenintech
60
3.9k
Transcript
46("3ͷΞʔΩςΫνϟ ಥܸʂʂྡͷΞʔΩςΫνϟ !TVHJUBOJ " 3 $ ) * 5 &
$ 5 6 3 &
લઆ
ࣗݾհ • ਿ୩ͱਃ͠·͢ • ܦྺ • υϫϯΰ χίχίੜ์ૹ • ηϓςʔχɾΦϦδφϧ
$50 ("/." • 46("3$50 46("3 !TVHJUBOJ
46("3ͱʁ • ஶ໊ਓʹಛԽͨ͠ϥΠϒ৴Ξ ϓϦ • ొͯ͠ΞʔςΟετΛϑΥϩʔ͠ ͓ͯ͘ͱి $BMM,JU ͕དྷΔ •
Ұఆ͕ϐοΫΞοϓ͞ΕબΤϦ ΞʹೖΔʢ௨শ͓ण࢘Ϩʔϯʣ • ΞʔςΟετ͕௨ରΛબͿͱ௨ ͕Ͱ͖Δ ଞͷਓͦͷ༷ࢠΛ ோΊΔ • ৴ऀ͕εΰ͘ͳ͚ΕΓཱ ͨͳ͍ • ৴ऀ͕Ϡό͍
ΞʔΩςΫνϟհ͡Ί·͢ ˞͝ҙ˞ %%%ͳͲ͍ΖΜͳ୯ޠ͕Ͱ͖ͯ·͕͢ ຊϓϨθϯςʔγϣϯฐࣾͷݱঢ়ͷհʹա͗ͣ Կ͔͠Βͷํ๏ͷਖ਼͍࣮͠ફํ๏Λࣔ͢ͷͰ͋Γ·ͤΜ
࠾༻ΞʔΩςΫνϟͱհൣғ 4DBMBαʔό 4XJGUJ04 ,PUMJO"OESPJE ͥΜͿΔ γεςϜΞʔΩςΫνϟ %*1Λ׆༻͢ΔҰʁ γεςϜΞʔΩςΫνϟ %*1Λ׆༻͢ΔҰʁ γεςϜΞʔΩςΫνϟ
%*1Λ׆༻͢ΔҰʁ (6*ΞʔΩςΫνϟ ແ͠ +40/ग़͚ͩ͢ (6*ΞʔΩςΫνϟ .7$͔ͳ͊ʜʁ (6*ΞʔΩςΫνϟ .77.ͩͱࢥͬͯΔ
ͲΕجຊతʹߏҰॹ TSD EPNBJO BQQMJDBUJPO BEBQUFS WJFX *OGSBTUSVDUVSF
Πϝʔδ͓ͳ͡Έͷԁܗ %PNBJO "QQMJDBUJPO "EBQUFS 7JFX ͦͷଞ *OGSBTUSVDUVSF
%PNBJO %PNBJO "QQMJDBUJPO "EBQUFS 7JFX ͦͷଞ *OGSBTUSVDUVSF %%%Ͱੜ͞ΕΔ֓೦ͷॅ·͏ॴ &OUJUZ7BMVF0CKFDU4FSWJDF 3FQPTJUPSZͷఆٛ
USBJUJOUFSGBDFQSPUPDPM Λஔ͘
"QQMJDBUJPO %PNBJO "QQMJDBUJPO "EBQUFS 7JFX ͦͷଞ *OGSBTUSVDUVSF υϝΠϯͷొਓΛ ҙຯͷ͋Δॲཧʹ·ͱΊΔΫϥεͷॅ·͏ॴ *OKFDU͞Εͨ%PNBJOΠϯελϯεΛͬͯͻͱ·ͱ·Γ
ͷॲཧʢྫσʔλΛ3FQPTJUPSZ͔ΒݺΜͰ4FSWJDFʹ௨ ͢ͳͲՃ͔ͯ͠Βอଘ͢Δ Λߦ͏࣮͔ఆٛΛஔ͘
"EBQUFS %PNBJO "QQMJDBUJPO "EBQUFS 7JFX ͦͷଞ *OGSBTUSVDUVSF υϝΠϯͷ࣮ͷॅ·͏ॴ υϝΠϯͷఆٛΛܧঝ࣮ͨ͠ʢ%#ʹ ΞΫηε͢Δ3FQPTJUPSZʣΛஔ͘
7JFX ͦͷଞʣ %PNBJO "QQMJDBUJPO "EBQUFS 7JFX ͦͷଞ *OGSBTUSVDUVSF 6*ͱίϯτϩʔϥ 6*7JFX$POUSPMMFS6*7JFX"DUJWJUZ'SB
HNFOU QMBZͷ $POUSPMMFSͳͲݟͨ ͱૢ࡞ͷ࢝·Γ͔ΒऴΘΓ·Ͱͷ੍ޚʹ ؔΘΔ࣮Λஔ͖·͢ɻ
*OGSBTUSVDUVSF %PNBJO "QQMJDBUJPO "EBQUFS 7JFX ͦͷଞ *OGSBTUSVDUVSF ൚༻తͳͷஔ͖ จࣈྻ࣌ࠁૢ࡞ϢʔςΟϦςΟɺ"84 ͷԿ͔͠ΒΛ͍͘͢ϥοϓͨ͠ͷ
ͷͲ͜Ͱ͑ͦ͏ͳ࣮Λஔ͘ɻ
ଆ͚ͩར༻Ͱ͖Δ %PNBJO "QQMJDBUJPO "EBQUFS 7JFX ͦͷଞ *OGSBTUSVDUVSF ґଘੑٯసͷݪଇΛ׆༻ %PNBJOr 7JFXɺ"EBQUFSɺ"QQMJDBUJPOΛར༻
JNQPSU Ͱ͖ͳ͍ "QQMJDBUJPOr %PNBJOΛར༻Ͱ͖Δɻ 7JFXɺ"EBQUFSΛར༻Ͱ͖ͳ͍ "EBQUFSr"QQMJDBUJPOɺ%PNBJOΛར༻Ͱ͖Δɻ7JFXΛར༻Ͱ͖ͳ͍ 7JFXr "EBQUFSɺ"QQMJDBUJPOɺ%PNBJOΛར༻Ͱ͖Δ *OGSBTUSVDUVSFr ଞΛར༻Ͱ͖ͳ͍ɻଞ͔Βར༻͞ΕΔ
%PNBJOͷਂ۷Γ
%PNBJOͷํ • υϝΠϯۦಈઃܭͰϞσϦϯάΛߦ͏ • &SJDຊʹͰ͖Δ͚ͩ४ڌͯ͠ݕ౼͢Δ • ʹग़ͯٞ͢͠Δ • ݪଇఆٛ USBJUJOUFSGBDFQSPUPDPM
Λஔ͘ • γϯϓϧͳ7BMVF0CKFDUʹྫ֎͋Δ • طͷΫϥε63-ΫϥεΛ͔ͭͬͨΓ • UZQFBMJBT'PP4USJOH TXJGULPUMJO "OZ7BM TDBMB Ͱදݱͨ͠Γ • &OVNͬͨΓ • ಉ͡ଘࡏʹରͯ͠αʔόͱΫϥΠΞϯτͰಉ͡ݴ༿ݟ͑ํʹ ͳΔͱݶΒͳ͍͜ͱʹؾΛ͚ͭΔ
ʮΞΧϯτΛ࣋ͬͨར༻ऀʯͷ ఆٛΠϝʔδ 4DBMB trait EntityId { /* … */ }
trait Entity[T <: EntityId] { val id: T } trait UserId extends EntityId trait ImageResource { /* … */ } case class UserName(value: String) extends AnyVal trait RegisteredUser extends Entity[UserId]{ val name: UserName val icon: ImageResource val registeredDate: LocalDateTime }
ʮΞΧϯτΛ࣋ͬͨར༻ऀʯͷ ఆٛΠϝʔδ 4DBMB trait EntityId { /* … */ }
trait Entity[T <: EntityId] { val id: T } trait UserId extends EntityId trait ImageResource { /* … */ } case class UserName(value: String) extends AnyVal trait RegisteredUser extends Entity[UserId]{ val name: UserName val icon: ImageResource val registeredDate: LocalDateTime } ొࡁΈͰͳ͍Ϣʔβʔ͍ͩͬͯΔͷҙ
trait Entity { type ID <: EntityId; val id: ID
} case class User(id: UserId, …) extends Entity { type ID = UserId } 5JQTɿ&OUJUZͱ*% ར༻ྫ ͕ͧ͘͞Μᐌ͘ ҙຯ ৽نͰ࡞Δ߹ͪ͜Βʹ͓͖ͯ͠·͠ΐ͏ʂ https://twitter.com/gakuzzzz/status/1103240324120403968
ʮΞΧϯτΛ࣋ͬͨར༻ऀʯͷ ఆٛΠϝʔδ 4XJGU protocol EntityId { /* … */ }
protocol Entity { var entityId: EntityId { get } } protocol UserId: EntityId { } typealias UserName = String protocol Profile: Entity { var userId: UserId { get } var name: UserName { get } var icon: URL? { get } } extension Profile { var entityId: EntityId { return userId } }
ʮΞΧϯτΛ࣋ͬͨར༻ऀʯͷ ఆٛΠϝʔδ 4XJGU protocol EntityId { /* … */ }
protocol Entity { var entityId: EntityId { get } } protocol UserId: EntityId { } typealias UserName = String protocol Profile: Entity { var userId: UserId { get } var name: UserName { get } var icon: URL? { get } } extension Profile { var entityId: EntityId { return userId } } ΫϥΠΞϯτ͔Β͢Εਓ͡Όͳͯ͘ ϓϩϑΟʔϧ͔͠ڵຯͳ͍ΑͶɺ ͷҙΛࠐΊ໋໊ͨ
ʮΞΧϯτΛ࣋ͬͨར༻ऀʯͷ ఆٛΠϝʔδ 4XJGU protocol EntityId { /* … */ }
protocol Entity { var entityId: EntityId { get } } protocol UserId: EntityId { } typealias UserName = String protocol Profile: Entity { var userId: UserId { get } var name: UserName { get } var icon: URL? { get } } extension Profile { var entityId: EntityId { return userId } } (FOFSJD1SPUPDPM໘͕ଟ͍ͷͰ খࡉͰར༻Λආ͚Δ
ʮΞΧϯτΛ࣋ͬͨར༻ऀʯͷ ఆٛΠϝʔδ ,PUMJO interface EntityId { /* ... */ }
interface Entity<ID : EntityId> { val id: ID } interface UserId: EntityId typealias UserName = String interface Profile: Entity<UserId> { val name:UserName val icon: URI? }
%%%తʹ͍͋͠ΫϥεୡډΔ • ΫϥΠΞϯτଆʹ͍Δ • 8FC3UD˞ • 8FC3UD%FWJDF8FC3UD4JHOBMJOH8FC3UD4FUUJOHʜ • )UUQ-JWF4USFBNJOH˞ •
"VEJP4PVSDF • 7JEFP4PVSDF • $BNFSB7JEFP4PVSDF4UJMM*NBHF7*EFP4PVSDF • %%%ͬΆ͘ͳ͍ʜ • ͔ͱ͍ͬͯݴ༿ͱͯ͠ઈର֎ͤͳ͍ʜ • Ͱศར ˞͜ΕΒࣗୡͷఆٛͨ͠ͷͰ ϥΠϒϥϦͷੜ0CKFDUΛࢦ͢ͷͰ͋Γ·ͤΜ
উखʹ૿ͨ͠ఆٛୡ ΫϥΠΞϯτଆͰͷΈ%PNBJOʹஔ͚ΔఆٛΛ૿͍ͯ͠Δ • -PDBM3FQPTJUPSZ • ϩʔΧϧͰ͔͠อଘ͠ͳ͍͔ΒͶʁ͍͍ͶʁΛڧௐͨ͠3FQPTJUPSZ • ओʹ$BDIF༻్Ͱ͏ͷͰ$MFBS$MFBS"MMΛ͍࣋ͬͯΔ • %BUB4PVSDF
• 3FQPTJUPSZͷѥछɻϩʔΧϧݶఆͷҰ࣌σʔλΛऔΓѻ͏ɻ • ߋ৽ݕग़ͷ EFMFHBUF FWFOU-JTUFS ΛηοτͰ͖Δ • 7JFXʹηοτ͢Δ༻ • %BUB4UPSF • %BUB4PVSDFͷ্Ґ൛ɻ • σʔλͷՃߋ৽͕Ͱ͖Δɻ
"QQMJDBUJPOͷਂ۷Γ
"QQMJDBUJPOͷΠϝʔδ 'PP3FQPTJUPSZ ࠩ͠ࠐΈޱ #BS3FQPTJUPSZ ࠩ͠ࠐΈޱ #B['BDUPSZ ࠩ͠ࠐΈޱ "4QFDJBM"QQMJDBUJPO 'PP3FQPTJUPSZ *NQMFNFOU
#BS3FQPTJUPSZ *NQMFNFOU #B['BDUPSZ *NQMFNFOU ͜ΕΛ ϝιου" ϝιου# ʜ
"QQMJDBUJPOͷΠϝʔδ 'PP3FQPTJUPSZ ࠩ͠ࠐΈޱ #BB3FQPTJUPSZ ࠩ͠ࠐΈޱ #B['BDUPSZ ࠩ͠ࠐΈޱ "4QFDJBM"QQMJDBUJPO 'PP3FQPTJUPSZ *NQMFNFOU
#BS3FQPTJUPSZ *NQMFNFOU #B['BDUPSZ *NQMFNFOU ͜͏͢Δͱ ϝιου" ϝιου# ʜ
"QQMJDBUJPOͷΠϝʔδ 'PP3FQPTJUPSZ ࠩ͠ࠐΈޱ #BB3FQPTJUPSZ ࠩ͠ࠐΈޱ #B['BDUPSZ ࠩ͠ࠐΈޱ "4QFDJBM"QQMJDBUJPO 'PP3FQPTJUPSZ *NQMFNFOU
#BS3FQPTJUPSZ *NQMFNFOU #B['BDUPSZ *NQMFNFOU ར༻Մೳʂ ར༻Մೳʂ ͜͏ͳΔʂ ϝιου" ϝιου# ʜ
"QQMJDBUJPOͷํ • %*͞Εͨ%PNBJOͷ࣮ΛΈ߹ΘͤͯԿ͔͠Βͷҙຯͷ͋ Δॲཧʹ͢Δ࣮Λஔ͘ • ଞͷ"QQMJDBUJPOΛड͚औΔࣄ͋ΔͷͰ࣮ଟ • ෭࡞༻ͷ͋ΔॲཧΛߦ͏͜ͱͳ͘ɺ%*͞ΕͨΠϯελϯ εͷࢦࣔΛ௨ͯ͠ߦ͏ •
λΠϚʔॲཧΛߦͬͨΓ"DUPSͰಈ͍ͯͨΓ͢Δ͜ͱ͋Γ݁ ߏࣗ༝
۩ମྫ r ܝࣔ൘ॻ͖ࠐΈΞϓϦ class CommentPoster(commentsRepository: CommentsRepository, commentFactory: CommentFactory){ def post(userId:UserId,
body:String, timestamp:LocalDateTime): Future[Done] ={ val comment = commentFactory.build(userId, body, timestamp) commentsRepository.store(comment) } } ˞ͿͬͪΌ͚͜Ε͘Β͍ͷॲཧͳΒ"QQMJDBUJPOΛ࡞Βͣ $POUSPMMFSʹॻ͍ͯ͠·͏͜ͱ͕ଟ͍
۩ମྫ r $BDIF͖3FQPTJUPSZ protocol FooRepository { func get(id: FooId) ->
Promise<Foo> func store(foo: Foo) -> Promise<Void> } protocol FooLocalRepository { func get(id: FooId) -> Promise<Foo> func store(foo: Foo) -> Promise<Void> func clear(id: FooId) func clearAll() } class CachedFooRepository: FooRepository { ʜ init(fooRepository: FooRepository, fooLocalRepository: FooLocalRepository) { ʜ } func get(id: FooId) -> Promise<Foo> { MPDBM3FQPTJUPSZ͔Βऔಘˠͳ͚ΕSFQPTJUPSZ͔Βऔಘ } func store(foo: Foo) -> Promise<Void> { SFQPTJUPSZʹอଘ͔ͯ͠Β MPDBM3FQPTJUPSZDMFBS } } ˞1SPNJTFϥΠϒϥϦ )ZESB ΛΜͰ͍ͬͯ·͢
۩ମྫ r $BDIF͖3FQPTJUPSZ interface FooRepository { suspend fun get(id: FooId):
Foo suspend fun store(foo: Foo) } interface FooLocalRepository { suspend fun get(id: FooId): Foo suspend fun store(foo: Foo) fun clear(id:FooId) fun clearAll() } class CachedFooRepository( private val fooRepository: FooRepository, private val fooLocalRepository: FooLocalRepository ) : FooRepository { override suspend fun get(id: FooId): Foo { /* localRepositoryから取得→なければrepositoryから取得 */ } override suspend fun store(foo: Foo) { /* repositoryに保存してから localRepository.clear() */ } }
۩ମྫ r $BDIF$MFBOFS class CacheCleaner( private val fooLocalRepository: FooLocalRepository, private
val barLocalRepository: BarLocalRepository, private val bazLocalRepository: BazLocalRepository ) { fun execute() { fooLocalRepository.clearAll() barLocalRepository.clearAll() bazLocalRepository.clearAll() } }
۩ମྫ r ϥΠϒ1MBZFSͷίΞ 1MBZFS6* EFMFHBUF ࠩ͠ࠐΈޱ Session ParticipantList DataStore ChatList
DataStore ͍ͬͯΔۀ • ঢ়گʹԠͯ͡)4-8FC35$ͷଓΛ͍͚ΔΑ͏$POOFDUJPOʹࢦࣔΛग़͢ • 8FC4PDLFU&WFOU4PVSDF͔ΒνϟοτࢀՃऀใΛड৴ͯ͠$IBU-JTU1BSUJDJQBOU-JTUʹ อଘ͢Δ • ϝιουΛ௨ͯ͠֎ଆʹ·ͱΊͨใΛฦͨ͠ΓɺࢦࣔΛड͚ͨΓ Connection WebRtc Signaling Device WebSocket CommandFactory HLS EventSource (server sent event) QMBZFS4UBUVT DIBUૹ৴ DMPTF ʜ
"EBQUFSͷਂ۷Γ
"EBQUFSͷํ • %PNBJOͷఆٛ USBJUJOUFSGBDFQSPUPDPM Λܧঝ࣮ͯ͠͠ ͨΫϥεͷஔ͖ • &OUJUZ7BMVF 0CKFDUͰ͋Ε DBTFDMBTTEBUBDMBTT
TUSVDUͰ࡞ͬͨΓ • +40/ͱͷ૬ޓม͜͜Ͱॻ͍ͯ͠·͏ • 3FQPTJUPSZͰ͋Ε%#"1*ͱ௨৴ͨ͠Γςετ༻ʹΦϯϝ ϞϦͷ࣮Λ࡞ͬͨΓɻ ͱ͘ʹͳ͍ͷͰ۩ମྫলུ͠·͢
7JFXͷਂ۷Γ
7JFX NJTD ͷํ • "QQMJDBUJPOΛΠϯελϯεԽͯ͠ը໘Λग़ྗߏங͢Δ • αʔόଆ+40/ు͚ͩ͘ͳͷͰγϯϓϧ • ΫϥΠΞϯτଆը໘ͷෳࡶ͞ʹԠͯ͡࿈ܞํ๏Λม͍͑ͯΔ •
ओͳॅਓ • 6*7JFX$POUSPMMFS6*7JFX"DUJWJUZ'SBHNFOU QMBZͷ $POUSPMMFS ͳͲͷίϯτϩʔϥʔܥ • 4UPSZCPBSE9JCMBZPVUͷ9.- σΟϨΫτϦతʹผʣ "1*ͷҾ ฦͷ+40/ૢ࡞ • %*ίϯςφ͜ͷ
αʔόଆͷ7JFX࣮ • جຊ3&45 "1*ܗࣜͰ+40/ฦ͚ͩ͢ • &OUJUZ7BMVF0CKFDUͱ+40/ͷ૬ޓม"EBQUFSͰ࣮͍ͯ͠Δ͜ͱ͋Δ͕ɺ ग़ྗͷ߹ʹҾͬுΒΕͨ͘ͳ͍ͷͰɺ͜ΕΒΛૉͷ··ฦ͢͜ͱগͳ͍ • جຊ"1*ຖʹฦܗࣜΛܾΊͯͦͪΒʹ٧Ίସ͑Δ import
play.api.libs.json.Json case class FooGetApiResponse(id: FooId, description: String) object FooGetApiResponse { implicit val jsonWrites = Json.writes[FooResponse] }
J04ͷ7JFX࣮ γϯϓϧͳը໘ • ؆୯ͳը໘Ͱ͋ΔͳΒͦͷ··7JFX$POUSPMMFSͱ4UPSZCPBSE͚ͬͭ͘Δ • 4UPSZCPBSEجຊը໘ຖʹ࡞ • Ұ࿈ͷը໘ʢΞϓϦىಈޙͷ͍Ζ͍ΖհϑϩʔͳͲʣෳը໘Λ֨ೲ 閉じるボタン
class FooViewController: UIViewController { @IBAction func onTouchUpInsideCloseBotton(_: Any) { navigationController?.popViewController(animated: true) } } 4UPSZCPBSE
J04ͷ7JFX࣮ ෳࡶͳը໘ • ଟগෳࡶͳΒ7JFXૢ࡞ΧελϜ7JFXʹԡ͠ࠐΊͯ͠·͏ • 7JFX$POUSPMMFSΧελϜ7JFXͷσʔληοτ SFQPTJUPSZΛݺͼग़͢ ͱɺ 7JFX͔Βͷૢ࡞ͷରԠ͕ओͳࣄɻ
Submit TextText TextTextTextTextText TextTextText TextText TextTextText 9JC ੜૢ࡞ !*#"DUJPO protocol FooViewDelegate: class { func onSubmit(value: String) } class FooView: UIView { /* ... */ weak var delegate: FooViewDelegate? var foo: Foo? { didSet { setNeedsLayout() } } override func layoutSubviews() { super.layoutSubviews() /* fooを描画 */ } } 'PP7JFX class FooViewController: UIViewController { @IBOutlet weak var fooView: FooView? { didSet { fooView?.delegate = self } } /* ... */ } extension FooViewController: FooViewDelegate { func onSubmit(value: String) { /* … */ } } 'PP7JFX$POUSPMMFS ᖤա͞Εͨ ૢ࡞ EFMFHBUF σʔλ ࢦࣔ QSPQFSUZTFU NFUIPEDBMM ඳը QSPQFSUZTFU
J04ͷ7JFX࣮ ෳࡶͳը໘ • 7JFX$POUSPMMFSͷࣄ͕ଟ͍ͳΒ"QQMJDBUJPOͷΫϥεʹ ͤͯ͠·͏ Submit TextText TextTextTextTextText TextTextText
TextText TextTextText 9JC ඳը QSPQFSUZTFU ੜૢ࡞ !*#"DUJPO σʔλ ࢦࣔ QSPQFSUZTFU NFUIPEDBMM ᖤա͞Εͨ ૢ࡞ EFMFHBUF class FooView: UIView { /* ... */ } 'PP7JFX class FooViewController : UIViewController, PlayerUI { /* ... */ } 'PP7JFX$POUSPMMFS 1MBZFS6* ͬͱ ᖤա͞Εͨ ૢ࡞ NFUIPEDBMM Πϕϯτ EFMFHBUF 1MBZFS$PSF
"OESPJEͷ7JFX࣮ γϯϓϧͳը໘ • ؆୯ͳը໘Ͱ͋ΔͳΒ,PUMJO"OESPJE&YUFOTJPOTͰ"DUJWJUZ ͔Β6*ύʔπΛͦͷ··ૢ࡞ YNM 閉じるボタン import kotlinx.android.synthetic.main.fooview.*
class FooActivity : FragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.fooview) buttonView.setOnClickListener { /* … */ } } }
"OESPJEͷ7JFX࣮ ෳࡶͳը໘ • ෳࡶͳը໘ͳΒͰ"OESPJE"SDIJUFDUVSF$PNQPOFOUTͷ 7JFX.PEFM-JWF%BUBͱ%BUB#JOEJOHΛ׆༻ • J04ͱൺֱ͢Δͱɺߏಉ͡ͰΧελϜ7JFXΛ࡞Βͳͯ͘ྑ͍໘͕ ຆͲʹͳΔΠϝʔδ YNM
Submit TextText TextTextTextTextText TextTextText TextText TextTextText class FooViewModel : ViewModel() { interface Listener { fun onSubmit() } var listener: Listener? by weakVar() val foo = MutableLiveData<Foo>() fun onClickSubmitButton() { listener?.onSubmit() } } ํ #JOEJOH class FooActivity : FragmentActivity() { override fun onCreate( savedInstanceState: Bundle?) { /* BindingとViewModelの⽤意 */ model.listener = this } } } σʔλ QSPQFSUZTFU ᖤա͞Εͨ ૢ࡞ EFMFHBUF
"OESPJEͷ7JFX࣮ ෳࡶͳը໘ • "DUJWJUZ'SBHNFOUͷࣄ͕ଟ͍ͳΒ"QQMJDBUJPOͷΫϥεʹ ͤͯ͠·͏ Submit TextText TextTextTextTextText TextTextText
TextText TextTextText 9JC σʔλ ࢦࣔ QSPQFSUZTFU NFUIPEDBMM ᖤա͞Εͨ ૢ࡞ EFMFHBUF class FooViewModel: ViewModel() { /* ... */ } 'PP7JFX.PEFM 'PP"DUJWJUZ 1MBZFS6* ͬͱ ᖤա͞Εͨ ૢ࡞ NFUIPEDBMM Πϕϯτ EFMFHBUF 1MBZFS$PSF class FooActivity : FragmentActivity(), PlayerUI { override fun onCreate() { /* … */ } } ํ #JOEJOH
հҎ্Ͱ͢ ԿͰͨ͠Ͱ͠ΐ͏͔ʁ
8FBSFIJSJOH IUUQTTVHBSDPSQKQ
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ