6 Design Patterns Every Android Developer Must Know
2023. 5. 3. 16:36ㆍ개발/Android
Singleton
- 오직 하나의 인스턴스만 허용함
- 응용프로그램의 모든 부분에서 액세스가 가능
- singleton클래스는 외부 코드에 의존하지 않고, 자체 인스턴스를 생성해야함
- singleton 클래스는 인스턴스가 스레드로부터 안전한지 확인해야함
- 키 속성을 유지하면서, 필요한 경우 쉽게 확장하거나 하위 클래스로 분류할 수 있느 방식으로 설계되어야함
lass Singleton private constructor() {
companion object {
private var instance: Singleton? = null
fun getInstance(): Singleton {
if (instance == null) {
instance = Singleton()
}
return instance!!
}
}
}
- DB나 네트워크 연결같은….인스턴스가 하나만 있어야하는 시나리오에 유용하다~
Factory
- 인터페이스를 상속받지만, 하위클래스에서 생성될 객체의 유형을 변경할 수 있는것
interface Shape {
fun draw()
}
class Circle: Shape {
override fun draw() {
println("Drawing a Circle")
}
}
class Square: Shape {
override fun draw() {
println("Drawing a Square")
}
}
class ShapeFactory {
fun getShape(shapeType: String): Shape? {
return when (shapeType.toLowerCase()) {
"circle" -> Circle()
"square" -> Square()
else -> null
}
}
}
- 클래스가 생성해야하는 객체 유형을 예상할 수 없거나, 클래스가 객체 생성 책임을 하위 클래스에 위임하려는 경우에 사용
Builder
- 복잡한 객체를 단계별로 구성할 수 있는 생성 디자인 패턴~
- 고유 메서드로만 인스턴스화가 가능.. 기본 혹은 전용 생성자가 존재해야한다
- 빌더클래스에는 구성중인 최종 개체를 반환하는 메서드가 있어야한다~
- 생성되는 최종 개체에는 클라이언트가 개체 생성을 시작할 수 있도록, 빌더 클래스의 새 인스턴스를 반환하는 정적 메서드 또는 팩토리 메서드를 제공해야함
- 빌더클래스는 변경이 안 되어야한다. 속성이 변경되지않아야한다..
class User {
var firstName: String? = null
var lastName: String? = null
var age: Int? = null
var phone: String? = null
var address: String? = null
override fun toString(): String {
return "User(firstName=$firstName, lastName=$lastName, age=$age, phone=$phone, address=$address)"
}
}
class UserBuilder {
private var firstName: String? = null
private var lastName: String? = null
private var age: Int? = null
private var phone: String? = null
private var address: String? = null
fun setFirstName(firstName: String) = apply { this.firstName = firstName }
fun setLastName(lastName: String) = apply { this.lastName = lastName }
fun setAge(age: Int) = apply { this.age = age }
fun setPhone(phone: String) = apply { this.phone = phone }
fun setAddress(address: String) = apply { this.address = address }
fun build() = User().apply {
firstName = this@UserBuilder.firstName
lastName = this@UserBuilder.lastName
age = this@UserBuilder.age
phone = this@UserBuilder.phone
address = this@UserBuilder.address
}
- 복잡한 객체를 생성해야할 때
Facade
- 시스템 작업을 위해 통합된 상위 수준의 api를 제공하는 패턴
interface UsersApi {
@GET( "userss" )
fun listUsers () : Call<List<User>>
}
DI
- 이제 이거 그만 말할때 된 것 같음
interface Logger {
fun log(message: String)
}
class ConsoleLogger : Logger {
override fun log(message: String) {
println(message)
}
}
class UserService(private val logger: Logger) {
fun createUser(username: String) {
// Code to create a user
logger.log("User $username created")
}
}
fun main() {
val userService = UserService(ConsoleLogger())
userService.createUser("demo")
// Output: User demo created
}
클래스내에서 인스턴스 생성하지않고, 생성자를 통해 받아서 사용함. 내부 코드에 영향을 주지않고, 변경이 용이
Adapter
- 원래 객체의 인터페이스를 새 인터페이스에 적응시키는 방법. 호환되지 않는 인터페이스를 함께 작동할 수 있게함~
interface MediaPlayer {
fun play(fileType: String, fileName: String)
}
class MP3Player : MediaPlayer {
override fun play(fileType: String, fileName: String) {
if (fileType == "mp3") {
println("Playing MP3 file: $fileName")
} else {
println("Invalid file format")
}
}
}
class MediaAdapter(private val mediaType: String) : MediaPlayer {
private val vlcPlayer = VLCPlayer()
private val mp4Player = MP4Player()
override fun play(fileType: String, fileName: String) {
when (mediaType) {
"vlc" -> vlcPlayer.playVLC(fileName)
"mp4" -> mp4Player.playMP4(fileName)
else -> println("Invalid media format")
}
}
}
class VLCPlayer {
fun playVLC(fileName: String) {
println("Playing VLC file: $fileName")
}
}
class MP4Player {
fun playMP4(fileName: String) {
println("Playing MP4 file: $fileName")
}
}
class AudioPlayer : MediaPlayer {
private val mediaAdapter = MediaAdapter("")
override fun play(fileType: String, fileName: String) {
when (fileType) {
"mp3" -> MP3Player().play(fileType, fileName)
"vlc", "mp4" -> mediaAdapter.play(fileType, fileName)
else -> println("Invalid media format")
}
}
}
fun main() {
val audioPlayer = AudioPlayer()
audioPlayer.play("mp3", "music.mp3")
// Output: Playing MP3 file: music.mp3
audioPlayer.play("vlc", "video.vlc")
// Output: Playing VLC file: video.vlc
audioPlayer.play("mp4", "movie.mp4")
// Output: Playing MP4 file: movie.mp4
audioPlayer.play("avi", "file.avi")
// Output: Invalid media format
}
Common Architectures
- MVC : 컨트롤러가 모델과 뷰를 업데이트하는 구조. 컨트롤러가 업데이트한 모델은 뷰가 그걸 참조해서 보여줌
- MVP : 위와 비슷하지만.. 모델에서 뷰를 분리했음. 프레젠터가 갱신까지 해줌~
- MVVM : 알지? .. 위와 비슷하지만 뷰에 대한 데이터 공급과, 모델에서 뷰 추상화를 담당하는 뷰모델이 생겨남.
- 클린 아키텍쳐~ : 어플리케이션을 별개의 레이어로 구분( 데이터 / 도메인 / 프리젠테이션 )
- 컴포넌트 기반 아키텍쳐 : MSA
- 이벤트 기반 아키텍쳐 : 각 구성요소는 특정 이벤트를 수신하고, 일부 작업을 수행하며, 새 이벤트를 전송해 이벤트에 반응 ( MVI랑 비슷..한가?)
'개발 > Android' 카테고리의 다른 글
Memory leaks (0) | 2023.07.25 |
---|---|
Data Store (0) | 2023.07.25 |
알아두면 좋은 Kotlin extension (0) | 2023.05.03 |
DiffUtil로 RecyclerView효율화하기 (0) | 2023.05.03 |
onBackPressed() deprecated issuede (0) | 2023.03.10 |