본문 바로가기

안드로이드/디자인패턴

SOILD 원칙

1. 단일 책임 원칙 (SRP)

각 클래스는 하나의 책임만 갖고 있어야 한다.

책임 별로 클래스를 분리함으로써 각 책임에 변경사항이 발생될 때만 해당 클래스만 변경하면 된다.

 

적용 전

class 회사{
    fun 영업(){...}
    fun 개발(){...}
    fun 인사(){...}
}

 

적용 후

class 영업{
    fun 업무(){...}
}

class 개발{
    fun 업무(){...}
}

class 인사{
    fun 업무(){...}
}

 

안드로이드에서의 SRP

1. ViewModel은 UI 데이터 상태를 관리하는 역할로만 사용한다.

 

2. 개방 폐쇄 원칙 (OCP)

확장에는 열려있고, 변경에는 닫혀 있어야 한다.

하나의 기능을 갖고 있지만 여러가지 경우에 따라 작업이 달라지는 경우라면 메서드가 복잡해지거나, 추가 또는 변경 사항이 있을 경우 실수로 기존의 작업에 영향을 줘 이미 사용되던 부분에 문제를 발생시킬 수 있다.

따라서 공통 된 작업을 나타내는 인터페이스 또는 추상 클래스를 상속받는 별도의 클래스를 각각의 경우마다 생성하여 구현한다.

 

적용 전

class Factory {
    fun generate(something: String){
        when(something){
            is pencil-> {}
            is car -> {}
            is clothes -> {}
            ...
        }
    }
}

 

적용 후

interface Factory{
    fun generate()
}

class Pencil: Factory{
    override generate(){...}
}

class Car: Factory{
    override generate(){...}
}

class Clothes: Factory{
    override generate(){...}
}

 

 

3. 리스코프 치환 원칙 (LCP)

자식 클래스는 언제나 부모 클래스를 대체할 수 있어야 한다.

부모를 상속 받는 자식 클래스에 따라 변동이 있는 메서드라면 이는 인터페이스로 따로 정의하여 사용하는 클래스에만 상속을 하여 구현할 수 있다.

 

적용 전

open class Bird {
    fun fly(){...}
    fun eat(){...}
}

class Penguin: Bird(){
    override fly(){
        throw Exception(...)
    }
}

 

적용 후

interface Flyable{
    fun fly()
}

open class Bird{
    fun eat(){...}
}

class Penguin: Bird(){...}

class Eagle: Bird(), Flyable{
    override fly(){...}
}

 

 

4. 인터페이스 분리 원칙 (ISP)

자신이 사용하지 않는 메서드를 구현하도록 강요받지 않아야 한다.

클래스와 마찬가지로 인터페이스 또한 책임에 따라 분리해줄 필요가 있다.

 

적용 전

interface License{
    fun car()
    fun bike()
}

class A: License{
    override car(){...}
    override bike(){...} // A는 오토바이가 필요 없음
}

 

적용 후

interface CarLicense{
    fun car()
}

interface BikeLicense{
    fun bike()
}

class A: CarLicense{
    override car(){...}
}

class B: CarLicense, BikeLicense{
    override car(){...}
    override bike(){...}
}

 

5. 의존성 역전 원칙 (DIP)

고수준 모듈이 저수준 모듈에 의존해서는 안 된다.

인터페이스 또는 추상 클래스를 선언하여 이를 상속 받는 클래스를 생성한 뒤, 이를 사용할 때 인터페이스 또는 추상 클래스를 타입으로 정의하여 사용하여 의존을 해결한다.

 

적용 전

class Human{
    fun move(dir: Int){...}
}

class Action{
    private lateinit var target: Human // 타입이 Human 클래스
	
    fun setTarget(target: Human){ this.target = target }
    fun go(){ target.move(1) }
    fun back(){...}
    fun left()
    fun right()
}

 

적용 후

interface Action{
    fun go()
    fun back()
    fun left()
    fun right()
}

class Human: Action{
    override fun go()
    override fun back()
    override fun left()
    override fun right()
}

class Control{
    private lateinit var target: Action // Action 인터페이스를 타입으로
	
    fun setTarget(target: Action){ this.target = target }
	
	fun go(){ tartget.go() }
	
    ...
}

'안드로이드 > 디자인패턴' 카테고리의 다른 글

Data Layer  (0) 2025.03.09
SingleTon  (0) 2025.03.08
함수형 프로그래밍  (0) 2024.08.13
[Java] 객체 지향  (0) 2024.01.24
[디자인 패턴] MVVM  (0) 2023.11.03