Mar 08, 2021, TIL (Today I Learned)

Inwoo Hwang·2021년 8월 26일
0
post-thumbnail

학습내용


디자인 패턴이란?

설계할 때 자주 쓰이는 템플릿. 선배들의 삽질기록.

코드의 모양새

Design Patterns(1994) by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides

디자인 패턴의 의미

  • OOP의 다양한 문제상황에 대한 예방
  • 프로그래머 사이의 협업효율 향상
  • 프로그래머 사이의 의사소통 증진
  • 코드의 안정화 및 최적화
  • 코드의 재사용성 증가

단, 적절히 잘 사용하자

디자인 패턴을 수단으로 사용해야지 목적으로 사용하면 주객전도되는 상황이 생길 수도 있다.

*주어진 패턴을 상황에 맞게 변경을 해서 사용해야 하는데 디자인 패턴에 집착하게 되면 유연하게 패턴을 적용 및 변경을 못하게 된다. 따라서 100퍼센트 지킬 필요는 없지만 명확하게 알아두면 쓸 일이 많다.

Design Patterns vs Architectures

  • Architecture: 큰 그림, 소프트웨어의 전반적인 큰 그림

    ​ ex) 서양 건축물 양식, MVC architecture

  • Design Pattern: 이 Architecture 안에서 세세한 부분을 해결하는 해결방식

    ​ ex) 서양 건축물 안의 불편한 설계부분을 수정해서 현재에 맞게 적용하는 것.

UML (Unified Modeling Language)

  • 구조를 표현하는 다이어그램
    • Class diagram
    • Object diagram
    • Component diagram
    • Deployment diagram
  • 동작을 표현하는 다이어그램
    • Use Case diagram
    • Sequence diagram
    • Collaboration diagram
    • State-chart diagram
    • Activity diagram
  • 모델 관리를 나타내는 다이어그램
    • Package diagram
    • Model diagram
    • Subsystem diagram

Swift는 어떠한 요소를 가지고 Architecture & 디자인 패턴을 만들었는가?

MVC (Model-View-Controller) Architecture

  • 무슨 기준으로 나누었나?

    • 화면을 다루는지, 데이터를 다루는지, 중간다리인지 기준을 두고 나눈다.
  • 기준을 나누는 요소들은 무엇인가?

    • 보이는 모든 요소는 객체(Object)이다.
  • Model, View, 그리고 Controller

    • Model은 데이터를 다루는 것을 정의 하는 것

    • 사용자에게 보이는 것은 전부 view라는 영역에 속하는 instance

      *view와 view controller는 다르다!!

계산된 프로퍼티 또는 연산 프로퍼티란(Computed Properties)?

"저장 프로퍼티뿐 아니라 추가적으로 클래스, 구조체, 열거형은 *계산된 프로퍼티를 선언할 수 있습니다. 이 계산된 프로퍼티는 실제 값을 저장하고 있는 것이 아니라 getteroptionalsetter를 제공해 값을 탐색하고 간접적으로 다른 프로퍼티 값을 설정할 수 있는 방법을 제공합니다."

출처: 프로퍼티 (Properties) - The Swift Language Guide (한국어) (gitbook.io)

  • 해당 프로퍼티는 실제 값을 저장하는 프로퍼티가 아니다. 다만 특정한 상태에 따른 값을 연산하는 프로퍼티이다.
  • 해당 프로퍼티는 두가지 역할을 가지고 있다.
    • 접근자 (getter)
      • 인스턴스의 내/외부 값을 연산하여 적절한 값을 돌려주는 역할
    • 설정자 (setter)
      • 은닉화된 내부의 프로퍼티 값을 간접적으로 설정하는 역힐

도대체 왜 메소드를 쓰지 않고 연산프로퍼티를 쓰는가?

메소드를 통해 인스턴스 값을 접근하려면 두 개의 메소드를를 구현해야 한다. 해당 인스턴스에 접근해 주는 메서드와 해당 인스턴스를 설정 해 주는 메소드 이렇게 두가지를 구현해 주어야 하는데 이 메서드가 분산 구현되기 때문에 코드의 가독성이 저하될 가능성이 있기 때문에 이런경우 연산프로퍼티를 쓰는 것이 더 간편하고 직관적이게 코드를 만들어준다.

구조체 예제는 책과 여러 블로그에 많이 나와 있기에 클래스 내부의 값을 특정한 상태에 다른 값을 연산하는 접근자(getter)와 설정자(setter) 역할을 하는 메소드를 활용하여 코드를 작성 해 봤다.

내 가상의 지갑상황을 가지고 코드문을 작성해 봤다.

역시 부모님께 잘해야겠다는 생각이 들었다.

import Foundation

class MyWallet {
    var money: Int
    var card: String
    
    init(won: Int, checkCard: String) {
        self.money = won
        self.card = checkCard
    }
    
    func supportFromParents() -> MyWallet {
        return MyWallet(won: 200000, checkCard: "신한카드")
    }
    
    func putMoneyInMyWallet(_ support: MyWallet) {
        money += support.money
        card = support.card
    }
}

var myProperty: MyWallet = MyWallet(won: 200, checkCard: "신용 카드가 없습니다.")

print("지금 저는 \(myProperty.card) 그리고 제 지갑에는 \(myProperty.money)원 밖에 없습니다. ")
print("제가 불쌍한지 부모님이 \(myProperty.supportFromParents().card) 그리고 \(myProperty.supportFromParents().money)원을 지원 해 주셨습니다.")

myProperty.putMoneyInMyWallet(myProperty.supportFromParents())
print("그래서 제 총 자산은 \(myProperty.money)원이 되었고 이제 \(myProperty.card)도 있습니다.")

// 지금 저는 신용 카드가 없습니다. 그리고 제 지갑에는 200원 밖에 없습니다.
// 제가 불쌍한지 부모님이 신한카드 그리고 200000원을 지원 해 주셨습니다.
// 그래서 제 총 자산은 200200원이 되었고 이제 신한카드도 있습니다.

해당 메소드를 연산프로퍼티와 비교해 보자.

class MyWallet {
    var money: Int
    var card: String
    
    init(won: Int, checkCard: String) {
        self.money = won
        self.card = checkCard
    }
    
    var supportFromParents: MyWallet { //연산 프로퍼티
        // 접근자
        get {
            return MyWallet(won: 200000, checkCard: "신한카드")
        }
        // 설정자
        set (support) {
            money += support.money
            card = support.card
        }
      // 매개 변수 이름을 생략한 설정자는 아래와 같이 설정할 수 있다.
        set {
              money += newValue.money
              card = newValue.card
          }
    }
}
// My Tung Tung empty Wallet
var myProperty: MyWallet = MyWallet(won: 200, checkCard: "신용 카드가 없습니다.")

// GET financial supoprt from parents, thank God
print("지금 저는 \(myProperty.card) 그리고 제 지갑에는 \(myProperty.money)원 밖에 없습니다. ")
print("제가 불쌍한지 부모님이 \(myProperty.supportFromParents.card) 그리고 \(myProperty.supportFromParents.money)원을 지원 해 주셨습니다.")

// SET changes in my Pocket
myProperty = myProperty.supportFromParents

print("그래서 제 총 자산은 \(myProperty.money)원이 되었고 이제 \(myProperty.card)도 있습니다.")
// 그래서 제 총 자산은 200000원이 되었고 이제 신한카드도 있습니다.

get 부분 같은경우 변화를 주는 값이라는 느낌이 오고

set 부분은 변화가 적용된 값이라고 느낌을 받았다.

메소드를 활용할 때 접근자와 설정자를 호출할 때 다른 두 개의 메소드를 활용해야 했었는데 연산프로퍼티를 활용할 경우 하나의 변수를 활용하여 접근하기에 훨씬 수월하다는 느낌을 받았다.

더 나아가 연산프로퍼티를 읽기 전용으로 구현하려면 get 메소드만 사용하면 된다.

class iOSCamperInformation {
    var gitHubIdAndAge: [String: Int]
    
    init(gitHubIdAndAge: [String: Int]) {
        self.gitHubIdAndAge = gitHubIdAndAge
    }
	
    // 아래와 같이 하면 return 값이 iOSCamperInformation type이다 
   	var james: iOSCamperInformation { //연산 프로퍼티
        // 접근자
        get {
            return iOSCamperInformation(gitHubIdAndAge: ["James": 27])
        }
      
    var yagom: iOSCamperInformation {
        get {
          return iOSCamperInformation(gitHubIdAndAge: ["yagom": 22])
        }
      }
    }
}
// create camperMembers instance
var camperMembers: IOSCamper = IOSCamper(gitHubIdAndAge: ["camper": 13])

// GET james
camperMembers = camperMembers.james

print(camperMembers.gitHubIdAndAge) // ["James", 27]

// SET이 설정되어 있지 않기 때문에 error!!
camperMembers = camperMembers.gitHubIdAndAge

TIL 예문을 작성하기 전까지는 굳이 메소드를 두고 왜 연산프로퍼티를 쓰는지 의문이 들었지만 쓰다보니 정말로 간편하다는 것을 깨달았다. 앞으로 자주 애용해야겠다.

참고문헌:

스위프트 프로그래밍 3판 - 야곰

내 가상의 지갑사정

문제점 / 고민한 점


야곰책의 예문과 인터넷에 올라온 예제 코드를 보면 솔직히 머리에도 잘 안들어오고 배운다는 느낌을 안 받았다. 그래서 오늘 연산프로퍼티를 몇 번이고 읽어봤지만 매우 헷갈렸다.

해결 방법


그런 상황에서 내 상상력을 활용하여 나만의 코드 예제를 만들고 해당 문법을 활용하니 머리속에도 더 잘 들어오고 내것으로 어느정도 흡수했다는 느낌을 받았다. 단순히 복사 붙여넣기로 다른사람의 예제를 TIL에 적기보다 앞으로도 이렇게 자주 나만의 코드예제를 만들어서 책과 인터넷에서 배운 내용을 능동적으로 학습해야겠다고 다짐했다.

profile
james, the enthusiastic developer

0개의 댓글