VisualStudio와 GitHub 연동하기

 

VisualStudio를 GitHub에 연동하는 방법을 알아봅니다.

 

 

 

0. GitHub 원격 저장소 생성 및 VS2019 설치

 

GitHub에 로그인한 후 사용할 원격 저장소를 미리 생성해 둡니다.

 

 

사용할 VS를 준비합니다. 해당 예시에서는 VS2019 CE버전을 사용하였습니다.

 

 

 

 

1. GitHub Extension 설치

 

VS2019를 킨 후 확장 -> 확장 관리를 연 후 "GitHub Extension for Visual Studio"를 설치합니다.

 

다운로드 버튼을 클릭한 후 VS2019를 끄면 자동으로 설치를 시작합니다.

 

 

 

2. 저장소 복제

 

재시작 후 "팀 탐색기" 창을 열어보면 "호스티드 서비스 공급자"에 "GitHub"이 추가된 것을 확인할 수 있습니다.

 

 

 

 

 

 

 

 

 

 

 

"연결..."을 클릭해 GitHub에 로그인 합니다. 성공적으로 연결이 되면 "팀 탐색기"에 "GitHub"이 추가됩니다.

 

이미 Git 원격 저장소가 있다면 "복제"를, 원격 저장소를 새로 만들려면 "만들기"를 클릭합니다. 

 

 

 

 

 

 

 

 

 

사용할 저장소를 선택 한 후 로컬 경로를 지정합니다. 

이후 "복제"버튼을 클릭합니다.

 

 

 

복제에 성공하면 "팀 탐색기"에서 좌측과 같은 화면을 확인할 수 있습니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

3. 솔루션 생성 및 커밋

 

처음 생성된 저장소를 복제한 경우 빈 폴더만 생성됩니다.

팀 탐색기 -> 솔루션 -> 새로 만들기를 선택해 솔루션을 생성합니다.

 

솔루션을 생성한 후 "프로젝트"의 "변경 내용"을 선택합니다.

 

 

 

 

 

커밋 메시지를 입력합니다. 하단의 변경내용을 확인한 후 "모두 커밋" 버튼을 클릭해 커밋 작업을 수행합니다.

 

만약 해당 변경 내용을 바로 푸시하고 싶다면 "모두 커밋" 버튼의 삼각형을

눌러 "모두 커밋 후 푸시"를 선택합니다.

 

 

 

 

 

 

이후 GitHub을 확인하면 정상적으로 푸시된 것을 확인할 수 있습니다.

 

 

 

 

반응형

'Programming' 카테고리의 다른 글

Front-end: Tech Trends (2) - AMP, Babel, TypeScript  (0) 2019.12.10
Front-end: Tech Trends (1) - PWA, SPA, SEO  (0) 2019.12.10
[SPA] SPA에서 SEO 문제 해결  (2) 2019.10.04
[SPA] Single Page Application  (0) 2019.10.04
[Kotlin] 37. 제네릭  (0) 2019.09.17

References: 아하 프론트 개발기

SinglePageApplication에서 SerachEngineOptimization와 관련된 문제를 ServerSideRendering을 이용해 해결하는 방법에 대해 알아봅니다.

 

 

1. SSR(Server Side Rendering)

 

일반적인 웹페이지는 페이지를 이동할 때마다 새로운 페이지를 요청하고 서버에서 모든 탬플릿은 서버 연산을 통해서 렌더링하고 완성된 페이지 형태로 응답합니다. 이를 SSR이라 합니다.

 

 

 

2. 장단점

 

서버에서 완성된 페이지를 주기 때문에 검색엔진이 크롤링하기 매우 좋습니다.

 

그에 반해 매 페이지 요청마다 새로고침이 발생하며 서버에서 불필요한 탬플릿도 중복해서 로딩되고 렌더링에 따른 부하 문제가 발생합니다.

 

 

 

3. React에서의 SSR

 

next.js가 아주 좋은 해결책이 될 것이라 생각합니다.

공식 홈페이지에 따르면 Next.js 9가 불과 몇 달 전에 출시하였습니다.

자세한 내용은 Next.js 공식 홈페이지를 참고하시면 됩니다.

 

 

 

 

 

 

 

반응형

'Programming' 카테고리의 다른 글

Front-end: Tech Trends (1) - PWA, SPA, SEO  (0) 2019.12.10
VisualStudio와 GitHub 연동하기  (0) 2019.10.28
[SPA] Single Page Application  (0) 2019.10.04
[Kotlin] 37. 제네릭  (0) 2019.09.17
[Kotlin] 36. 연산자 오버로딩  (0) 2019.09.16

References: 아하 프론트 개발기

 

 

1. SPA

 

Single Page Application. 페이지가 하나만 있는 웹페이지.

Client Side Rendering 방식으로 생명주기동안 리소스를 딱 한번만 로딩한다.

그 이후부턴 데이터를 받아올때만 서버와 통신하며 페이지를 이동하면 기존 페이지 내부를 수정하여 보여준다.

 

 

 

2. 장점

 

  • 자연스러운 사용자 경험(UX)
  • 필요한 리소스만 부분적으로 로딩(성능)
  • 서버의 탬플릿 연산을 클라이언트로 분산(성능)
  • 컴포넌트별 개발 용이(생산성)
  • 모바일 앱 개발을 염두에 둔다면 동일한 API를 사용하도록 설계 가능(생산성)

 

3. 단점

 

  • JavaScript 파일을 번들링해서 한 번에 받기 때문에 초기 구동 속도 느림(webpack 의 code splitting으로 해결)
  • 검색엔진최적화(SEO)가 어려움 (SSR 로 해결)
  • 보안 이슈 (프론트엔드에 비즈니스 로직 최소화)

 

 

 

 

반응형

'Programming' 카테고리의 다른 글

VisualStudio와 GitHub 연동하기  (0) 2019.10.28
[SPA] SPA에서 SEO 문제 해결  (2) 2019.10.04
[Kotlin] 37. 제네릭  (0) 2019.09.17
[Kotlin] 36. 연산자 오버로딩  (0) 2019.09.16
[Kotlin] 35. 어노테이션 클래스  (0) 2019.09.16

 

1. Redux란 무엇인가.

 

한 문장으로 말하자면 "Redux는 상태를 좀 더 효율적으로 관리할 수 있게 해주는 라이브러리"입니다.

 

 

 

2. Flux 패턴

 

Redux 공식 홈페이지의 소개에 따르면 "Redux는 Flux의 중요한 특징들로부터 영감을 얻었습니다. Flux와 마찬가지로 Redux에서는 애플리케이션의 특정 레이어에 있을 모델 업데이트 로직에 집중할 수 있도록 해줍니다"라고 명시되어 있습니다.

그렇다면 Flux란 무엇일까요?

 

Flux 패턴은 MVC 패턴의 양방향 통신이 가진 복잡함을 제거하기 위해 컴포넌트 간 통신을 단일화시킨 패턴을 말합니다.

위의 그림과 같이 데이터는 디스패처에 의해 단방향으로 흐르게 되는 것이 Flux 패턴의 핵심입니다.

 

 

 

3. Redux

 

다시 Redux로 돌아와서 결국 Redux는 Flux패턴의 구현체 중 하나란 것이다.

물론 공식 홈페이지에 따르면 "Redux를 Flux의 구현 중 하나라고 생각할 수 있을까요? 그렇기도 하고, 아니기도 합니다."라고 적혀있습니다. 

Redux는 Flux패턴의 철학을 추구한 구현체가 맞습니다만 정확히 같지는 않습니다. 가장 큰 차이점은 Flux와 달리 Redux에는 디스패처라는 개념이 존재하지 않는다는 것입니다.

좀 더 명확히 하자면  "Flux는 (state, action) => state 형식으로 묘사되곤 합니다. 따라서 Redux 역시 Flux 아키텍처라고 이야기할 수 있지만, 순수 함수를 통해 이를 더 간단하게 만듭니다"라고 설명되어 있습니다.

 

 

 

 

반응형

References: Do it! 코틀린 프로그래밍

코틀린에서의 제네릭에 대해 알아봅니다.

 

 

1. 제네릭

 

제네릭(Generic)은 클래스 내부에서 사용할 자료형을 나중에 인스턴스를 사용할 때 확정합니다.

자료형의 객체들을 다루는 메서드나 클래스에서 컴파일 타임에 자료형을 검사해 적당한 자료형을 선택할 수 있도록 하기 위해 제네릭이 도입되었습니다.

제네릭을 사용하면 객체의 자료형을 컴파일 타임에 체크하므로 객체 자료형의 안정성을 높이고 형 변환의 번거로움이 줄어듭니다.

 

제네릭은 앵글 브래킷(<>) 사이에 형식 매개변수를 넣어 선언합니다.

이때 형식 매개변수는 하나 이상 지정할 수 있습니다.

형식 매개변수는 자료형을 대표하는 용어로 T와 같은 특정 영문의 대문자로 사용합니다. 이는 나중에 필요한 자료형으로 대체됩니다.

 

제네릭은 다양한 자료형을 다워랴하는 컬렉션에 많이 사용됩니다.

컬렉션은 List, Set, Map등으로 다수의 데이터를 다루는 특별한 클래스로 제네릭을 사용해 정의되어 있습니다.

 

다음 예시를 통해 제네릭에 대해 알아보겠습니다.

 

class Box<T>(t: T) { var name = t }
fun main() {
    val box1: Box<Int> = Box<Int>(1) // Box(1)
    val box2: Box<String> = Box<String>("Hello") // Box("Hello")
    println(box1.name)
    println(box2.name)
}

 

  • Box<T>(t: T): 제네릭 사용. 형식 매개변수로 받은 인자를 name에 저장.

 

위 코드를 실행하면 다음과 같은 결과를 확인할 수 있습니다.

형식 매개변수는 T입니다. T는 보통 Type을 줄인 것을 의미하며 강제적인 것은 아닙니다.

형식 매개면수는 관습적으로 다음을 사용합니다.

  • 요소(Element) - E
  • 키(Key) - K
  • 숫자(Number) - N
  • 형식(Type) - T
  • 값(Value) - V

 

앞선 예제에서의 Box<T>를 제네릭 클래스라고 합니다.

제네릭 클래스는 형식 매개변수를 하나 이상 받는 클래스입니다.

클래스를 선언할 때 자료형을 특정하지 않고 인스턴스를 생성하는 시점에서 자료형을 정합니다.

 

 

2. 자료형 변환

 

제네릭 클래스는 가변성을 지정하지 않으면 형식 매개변수에 상, 하위 클래스가 지정되어도 서로 자료형이 변환되지 않습니다.

다음 코드를 통해 확인해 보겠습니다.

 

open class Parent
class Child: Parent()
class Cup<T>
fun main() {
    val obj1: Parent = Child()
    val obj2: Child = Parent()
    val obj3: Cup<Parent> = Cup<Child>()
    val obj4: Cup<Child> = Cup<Parent>()
    val obj5 = Cup<Child>()
    val obj6: Cup<Child> = obj5
}

 

  • obj1: Parent 형식은 Child의 자료형으로 변환될 수 있습니다.
  • obj2: 자료형이 불일치해 오류가 발생합니다.
  • obj3: 자료형이 불일치해 오류가 발생합니다. 
  • obj4: 자료형이 불일치해 오류가 발생합니다.
  • obj5: obj는 Cup<Child> 자료형이 됩니다.
  • obj6: 자료형이 일치해 오류가 발생하지 않습니다.

 

obj3, obj4에서 보듯이 제네릭 클래스에서는 형식 매개변수인 T에 상위와 하위 클래스를 지정해도 서로 관련 없는 형식이 되어 형식이 일치하지 않는 오휴가 발생합니다.

또한 제네릭 형식 매개변수는 기본적으로 Null을 허용합니다. 만약 Null을 허용하지 않게 하고 싶다면 T: Any 형식을 사용하면 됩니다.

 

 

3. 제네릭 함수 및 메서드

 

형식 매개변수를 받는 함수나 메서드를 제네릭 함수 또는 메서드라고 합니다.

제네릭 함수나 메서드는 해당 함수나 메서드 앞에 <T>와 같이 형식 매개변수를 지정합니다.

<K, V>처럼 여러 형식 매개변수를 사용할 수도 있습니다.

자료형의 결정은 함수가 호출될 때 컴파일러가 자료형을 추론할 수 있습니다.

 

다음 예시를 통해 확인해 보도록 하겠습니다.

 

fun <T> find(a: Array<T>Target: T): Int{
    for( i in a.indices ) {
        if ( a[i] == Target ) { return i }
    }
    return -1
}
fun main() {
    val arr1: Array<String> = arrayOf("Apple", "Banana", "Cherry", "Durian")
    var arr2: Array<Int> = arrayOf(1, 2, 3, 4)
    println("arr.indices ${arr1.indices}")
    println(find<String>(arr1, "Cherry"))
    println(find(arr2, 2))
}

 

  • fun <T> find: 제네릭 함수
  • Array<T>: 배열을 위한 클래스
  • a.indices: a배열의 유효 범위

 

위의 코드를 실행시키면 다음과 같은 결과를 확인할 수 있습니다.

 

 

4. 제네릭과 람다식

 

형식 매개변수로 선언된 함구의 매개 변수를 연산할 경우 자료형을 경정할 수 없어 오류가 발생합니다.

 

fun <T> add ( a: T, b: T): T { 
    return a + b // 자료형을 아직 결정할 수 없어 오류 발생. 
}

 

하지만 람다식을 매개변수로 받으면 자료형을 결정하지 않아도 실행 시 람다식 본문을 넘겨줄 때 결정되므로 이런 문제를 해결할 수 있습니다.

 

다음과 같이 코드를 작성해 봅시다.

 

fun <T> add( a: T, b: T, op: ( T, T ) -> T ): T{
    return op( a, b )
}
fun main() {
    val result = add2, 3, { a, b -> a + b } )
    println(result)
}

 

  • op: ( T, T ) -> T: 매개변수에 람다식을 받습니다.
  • { a, b -> a + b }: 매개변수에 람다식을 전달합니다.

 

람다식은 add 함수가 실행될 때 넘겨지는 인자이므로 연산식을 함수 선언부에 직접 구현하지 않고 전달하는 방법을 사용합니다. 따라서 함수의 형식 매개변수의 자료형을 특정하지 않아도 실행 가능합니다.

 

함루의 람다식 매개변수를 좀 더 읽기 좋게 단순화할 수 있습니다.

다음 예제 코드는  typealias를 사용해 람다식 매개변수에 다른 이름을 사용한 예시입니다.

 

typealias arithmetic<T> = ( T, T ) -> T
fun <T> add( a: T, b: T, op: arithmetic<T> ): T{
    return op( a, b )
}
fun main() {
    val sumInt1: (Int, Int) -> Int = { a, b -> a + b }
    val sumInt2 = { a: Int, b: Int -> a + b
}

    val result = add(2, 3, { a, b -> a + b } )
    val result1 = add( 2, 3, sumInt1 )
    val result2 = add( 2, 3, sumInt2 )

    println(result)
    println(result1)
    println(result2)
}

 

  • typealias: typealias를 사용해 람다식 매개변수를 단순화하였습니다.
  • sumInt1, sumInt2: 람다식을 간소화 후 변수에 저장해 사용하였습니다.

 

 

 

 

반응형

References: Do it! 코틀린 프로그래밍

코틀린에서 연산자를 오버 로딩하는 법에 대해 알아봅니다.

오버 로딩에 대한 내용은 여기서 확인해 주세요.

 

 

1. 연산자 오버 로딩

 

말 그대로 오버 로딩을 연산자에 적용하는 것을 말합니다.

사실 코틀린에선 이미 여러 연산자가 많이 오버 로딩되어 있습니다.

 

'+'를 예시로 살펴보겠습니다.

지금까지 +연산을 직접 구현한 적이 있나요?

사실 A + B는 A.plus(B)와 같습니다. A와 B엔 다양한 자료형이 올 수 있습니다.

코틀린은 편의를 위해 이미 여러 자료형에 대해 오버 로딩을 구현해 두었습니다.

Byte, Short, Int, Long, Float, Double, Any 등 이미 오버 로딩된 '+'를 바로 사용할 수 있습니다.

 

만약 사용자가 정의한 객체에 대해 '+'연산을 수행하고 싶으면 어떻게 해야 할까요?

이런 경우에 연산장 오버 로딩이 필요합니다.

다음 예시를 통해 직접 정의한 클래스에 대해 연산자 오버 로딩을 해 봅시다.

 

class Point(var x: Int = 0, var y: Int = 0) {
    operator fun plus(p: Point): Point { return Point( x + p.x, y + p.y) }
}
fun main() {
    val p1 = Point(3, -8)
    val p2 = Point(2, 9)
    var point = Point()
    point = p1 + p2
    println("point = (${point.x}, ${point.y})")
}

 

Point 클래스에 대해서 plus 연산자를 오버 로딩하였습니다.

위의 코드를 실행하면 다음과 같은 결과를 확인할 수 있습니다.

 

* 연산자의 종류

  • a + b = a.plus(b)
  • a - b = a.minus(b)
  • a * b = a.times(b)
  • a / b = a.div(b)
  • a % b = a.rem(b)
  • a .. b = a.rangeTo(b)
  • ...

 

 

 

반응형

'Programming' 카테고리의 다른 글

[SPA] Single Page Application  (0) 2019.10.04
[Kotlin] 37. 제네릭  (0) 2019.09.17
[Kotlin] 35. 어노테이션 클래스  (0) 2019.09.16
[Kotlin] 34. 봉인 클래스와 열거형 클래스  (0) 2019.09.16
[Kotlin] 33. 내부 클래스  (0) 2019.09.16

References: Do it! 코틀린 프로그래밍

코틀린에서의 어노테이션 클래스에 대해 알아봅니다.

 

 

1. 어노테이션(Annotation) 클래스

 

어노테이션은 코드에 부가 정보를 추가하는 역할을 합니다.

@기호와 함께 나타내는 표기법입니다.

주로 컴파일러나 프로그램 런타임에서 사전 처리를 위해 사용합니다.

 

 

2. 어노테이션의 사용

 

사용자 정의 어노테이션을 만들기 위해서는 annotation 키워드를 사용해 클래스를 선언합니다.

선언한 어노테이션 클래스는 @기호와 함께 사용할 수 있습니다.

 

annotation class AnnoTest
...
@AnnoTest class MyClass{ ... }

 

어노테이션은 다음과 같은 속성을 사용해 정의될 수 있습니다.

  • @Target : 어노테이션이 지정되어 사용할 종류를 정의
  • @Retention : 어노테이션을 컴파일된 클래스 파일에 저장할 것인지 런타임에 반영할 것인지 정의
  • @Repeatable : 어노테이션을 같은 요소에 여러번 사용 가능하게 할지를 정의
  • @MustBeDocumented : API의 일부분으로 문서화하기 위해 사용.

위와 같은 속성과 함께 정의된 어노테이션 클래스의 예는 다음과 같습니다.

 

@Target( AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
             AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION )
@Retention( AnnotationRetention.SOURCE ) // or RUNTIME
@MustBeDocumented
annotation class AnnoTest

 

 

3. 어노테이션의 위치

 

어노테이션이 들어갈 수 있는 위치는 다음과 같습니다.

 

@AnnoTest class MyClass {
    @AnnoTest fun myMethod( @AnnoTest myProperty: Int): Int {
        return( @AnnoTest 1 )
    }
}

 

어노테이션은 클래스앞, 메서드 앞, 프로퍼티 앞에서 사용 가능하며 반환 시 반환 값 앞에 표기하고 소괄호로 감싸줍니다.

 

만약 생성자 앞에 어노테이션을 사용하면 constructor 키워드를 반드시 명시해야 합니다.

 

class MyClass @AnnoTest constructor( dependency: MyDependency ) { ... }

 

어노테이션은 게터/세터에서도 사용할 수 있습니다.

 

class MyClass {
    var x: MyDependendcy? = null
        @AnnoTest set
}

 

 

4. 어노테이션의 매개변수와 생성자.

 

어노테이션에 매개변수를 지정하려면 다음과 같이 생성자를 통해 지정할 수 있습니다.

 

annotation class Special( val why: String )
@Special( "example" ) class MyClass{ ... }

 

매개변수로 사용될 수 있는 자료형은 다음과 같습니다.

  • 기본 자료형
  • 열거형
  • 문자형
  • 기타 어노테이션
  • 클래스
  • 위의 목록을 갖는 배열

 

 

 

 

반응형

'Programming' 카테고리의 다른 글

[Kotlin] 37. 제네릭  (0) 2019.09.17
[Kotlin] 36. 연산자 오버로딩  (0) 2019.09.16
[Kotlin] 34. 봉인 클래스와 열거형 클래스  (0) 2019.09.16
[Kotlin] 33. 내부 클래스  (0) 2019.09.16
[Kotlin] 32. 데이터 클래스  (0) 2019.09.12

References: Do it! 코틀린 프로그래밍

코틀린에서의 봉인 클래스와 열거형 클래스에 대해 알아봅니다.

 

 

1. 봉인(Sealed) 클래스

 

실드(Sealed) 클래스는 미리 만들어 놓은 자료형들을 묶어서 제공합니다.

따라서 어떤 의미에서는 열거형(Enum) 클래스의 확장으로 볼 수도 있습니다.

 

실드 클래스는 sealed 키워드를 통해 선언할 수 있습니다.

실드 클래스는 추상 클래스와 같기 때문에 객체를 만들 수 없습니다.

실드 클래스는 private 이 아닌 생성자는 허용하지 않습니다.

실드 클래스는 같은 파일안에서만 상속을 허용합니다.

 

다음 예제를 통해 실드 클래스에 대해 알아보도록 하겠습니다.

 

sealed class Result{
    open class Success(val message: String): Result()
    class Error(val code: Int, val message: String): Result()
}
class Status: Result()
class Inside: Result.Success("Status")
fun eval(result: Result): String = when(result) {
    is Status -> "in progress"
    is Result.Success -> result.message
    is Result.Error -> result.message
}
fun main() {
    val result = Result.Success("Good!")
    val msg = eval(result)
    println(msg)
}

 

  • sealed class Result: 실드 클래스를 선언합니다.
  • class Stauts: Result(): 실드 클래스를 상속합니다. 같은 파일에서만 가능합니다.
  • class Inside: Result.Success("Status"): 내부 클래스 상속

위의 코드를 실행하면 다음과 같은 결과를 확인할 수 있습니다.

실드 클래스는 특정 객체 자료형에 따라 when문과 is에 의해 선택적으로 실행할 수 있습니다.

 

 

2. 열거형 클래스

 

열거형 클래스는 여러 상수를 선언하고 열거된 값을 조건에 따라 선택할 수 있는 특수한 클래스입니다.

 

열거형 클래스는 실드 클래스처럼 다양한 자료형을 다룰 순 없습니다.

열거형 클래스는 enum 키워드와 함께 선언됩니다.

열거형 클래스의 상수값은 매개변수를 통해 초기화될 수 있습니다.

열거형 클래스의 상수값의 끝은 세미콜론을 통해 알립니다.

열거형 클래스는 필요한 경우 메서드를 포함할 수 있습니다.

 

다음 코드를 통해 열거형 클래스에 대해 알아보도록 합시다.

 

enum class Color(val r: Int, val g: Int, val b: Int){
    RED(255, 0, 0), ORANGE(255, 165, 0), YELLOW(255, 255, 0),
    GREEN(0, 255, 0), BLUE(0, 0, 255), INDIGO(75, 0, 130), VIOLET(238, 130, 238);
    fun rgb() = (r * 256 + g) * 256 + b
}
fun getColor(color:Color) = when(color) {
    Color.RED -> color.name
    Color.ORANGE -> color.ordinal
    Color.YELLOW -> color.toString()
    Color.GREEN -> color
    Color.BLUE -> color.r
    Color.INDIGO -> color.g
    Color.VIOLET -> color.rgb()
}
fun main() {
    println(Color.BLUE.rgb())
    println(getColor(Color.BLUE))
}

 

  • enum class Color: enum 키워드를 이용해 열거형 클래스를 선언합니다.
  • VIOLET(238, 130, 238); : 세미콜론을 통해 끝을 알려줍니다.

위의 코드를 실행하면 다음과 같은 결과를 확인할 수 있습니다.

열거형 클래스에서 인터페이스의 메서드를 구현할 수도 있습니다.

다음 예제를 통해 인터페이스의 메서드를 구현하는 방법을 알아봅시다.

 

interface ScoreScore { fun getScore(): Int}
enum class MemberType(var prio: String): Score {
    NORMAL("Third"){ override fun getScore(): Int = 100},
    SILVER("Second"){ override fun getScore(): Int = 500},
    GOLD("First"){ override fun getScore(): Int = 1500}
}
fun main() {
    println(MemberType.NORMAL.getScore())
    println(MemberType.GOLD)
    println(MemberType.valueOf("SILVER"))
    println(MemberType.SILVER.prio)
    for( grade in MemberType.values() ){ println("grade.name = ${grade.name}, prio = ${grade.prio}") }
}

 

  • interface Score: 인터페이스를 선언합니다.
  • enum class MemberType: 인터페이스를 구현하는 열거형 클래스입니다.
  • for( grade in MemberType.values() ): 열거형 클래스의 모든 값을 가져오는 반복문입니다.

위의 코드를 실행하면 다음과 같은 결과를 확인할 수 있습니다.

 

 

 

 

 

반응형

'Programming' 카테고리의 다른 글

[Kotlin] 36. 연산자 오버로딩  (0) 2019.09.16
[Kotlin] 35. 어노테이션 클래스  (0) 2019.09.16
[Kotlin] 33. 내부 클래스  (0) 2019.09.16
[Kotlin] 32. 데이터 클래스  (0) 2019.09.12
[Kotlin] 31. 인터페이스  (0) 2019.09.12

References: Do it! 코틀린 프로그래밍

코틀린에서의 내부 클래스에 대해 알아봅니다.

 

 

1. 내부 클래스

 

내부 클래스는 클래스 내부에 클래스를 다시 정의하는 것을 말합니다.

내부 클래스는 독립적인 클래스로 정의하기 모호한 경우나 한 클래스의 내부에서만 사용하고 외부에선 접근할 필요가 없는 클래스를 정의하기 위해 사용합니다.

단, 이러한 내부 클래스는 남용하면 클래스의 의존성이 커지고 가독성이 저하되므로 주의가 필요합니다.

 

 

2. 중첩(Nested) 클래스

 

코틀린에서 내부 클래스를 정의하기 위한 방법 중 하나입니다.

코틀린에서 중첩 클래스는 기본적으로 적적 클래스처럼 다뤄집니다. 즉 객체 생성 없이 접근이 가능합니다.

 

다음 예제를 통해 확인해 보도록 하겠습니다.

 

class Outer{
    val ov = 5
    class NestedNested {
        val nv = 10
        fun greeting() = "[Nested] Hello! $nv"
    }
    fun outside() {
        val msg = Nested().greeting()
        println("[Outer] $msg, ${Nested().nv}")
    }
}
fun main() {
    val output = Outer.Nested().greeting()
    println(output)
    val outer = Outer()
    outer.outside();
}

 

  • class Nested: 중첩 클래스를 정의합니다.
  • $nv: 내부의 nv는 접근 가능하나 외부의 ov는 접근할 수 없습니다.
  • Nested().greetring: 정적 클래스 취급으로 객체 생성 없이 사용 가능합니다.
  • val outer = Outer(): 외부 클래스는 객체를 생성해야 접근 가능합니다.

위 코드를 실행하면 다음과 같은 결과를 확인할 수 있습니다.

 

만약 외부 내부 클래스에서 외부 클래스에 접근하고 싶으면 외부 클래스에 컴패니언 객체를 정의하면 됩니다.

컴패니언 객체는 static처럼 접근이 가능하므로 중첩 클래스에서 접근이 가능합니다.

 

예를 들어 다음과 같은 경우엔 중첩 클래스에서 외부 클래스의 프로퍼티에 접근할 수 있습니다.

 

class Outer{
    val ov = 5
    class Nested{
        val nv = 10
        fun gretting() = "[Nested] Hello! $nv"
        fun accessOuter() = println("Country: $country")
    }
    fun outside() {
        val msg = Nested().gretting()
        println("[Outer] $msg, ${Nested().nv}")
    }
    companion object{
        const val country = "Korea"
    }
}

 

  • const val country: 외부에 존재하는 클래스에 컴패니언 객체를 선언하였습니다.

위와 같이 컴패니언 객체 내부의 프로퍼티는 중첩 클래스에서 접근할 수 있습니다.

   

 

3. 이너(Inner) 클래스

 

이너 클래스는 inner라는 선언자를 통해 정의할 수 있습니다.

inner를 통해 선언된 이너 클래스는 외부 클래스의 멤버에 접근할 수 있습니다.

심지어 private멤버까지도 사용할 수 있습니다.

 

다음 예시를 통해 확인해 보도록 하겠습니다.

 

class SmartPhone(val model: String){
    private val cpu = "Snapdragon"
    inner class ExternalStorage(val size: Int){
        fun getInfo() = "${model}: Installed on $cpu with ${size}${size} GB"
    }
}
fun main() {
    val mySdcard = SmartPhone("Note9").ExternalStorage(256)
    println(mySdcard.getInfo())
}

 

  • inner class ExternalStorage: 이너 클래스에서는 외부 클래스의 멤버에 접근 가능합니다.

위의 코드를 실행시키면 다음과 같은 결과를 확인할 수 있습니다.

이너 클래스에선 외부 클래스의 private멤버를 사용할 수 있는 것을 확인할 수 있습니다.

 

 

4. 익명 객체

 

자바에서는 익명 이너 클래스를 통해 일회용 객체를 생성하였습니다.

코틀린에서는 object 키워드를 사용하는 익명 객체로 같은 기능을 수행할 수 있습니다.

자바와의 차이점은 다중 인터페이스를 통한 구현이 가능하는 것입니다.

 

다음 예제를 통해 확인해 보도록 하겠습니다.

 

interface SwitcherSwitcher { fun on(): String }
class SmartPhone(val model: String){
    private val cpu = "Snapdragon"
    inner class ExternalStorage(val size: Int){ fun getInfo() = "${model}: Installed on $cpu with ${size}GB" }
    fun powerOn(): String {
        class Led(val color: String){ fun blink(): String = "Blinking $color on $model" }
        val powerStatus = Led("Red")
        val powerSwitch = object: Switcher {
            override fun on(): String { return powerStatus.blink() }
        }
        return powerSwitch.on()
    }
}
fun main() {
    val myPhone = SmartPhone("Note9")
    myPhone.ExternalStorage(256)
    println(myPhone.powerOn())
}

 

  • interface switcher: 인터페이스 선언
  • object: Switcher: 익명 객체 사용
  • override fun on: 인터페이스의 메서드 구현
  • powerSwitch.on(): 익명 객체의 메서드 사용

위의 코드를 실행하면 다음과 같은 결과를 확인할 수 있습니다.

 

 

 

 

 

반응형

References: Do it! 코틀린 프로그래밍

코틀린에서의 데이터 클래스에 대해 알아봅니다.

 

 

1. 데이터 클래스

 

데이터 클래스는 데이터 전달을 위한 클래스라고 말합니다. 

보통 이러한 객체를 DTO(Date Transfer Object)라고 부릅니다.

DTO는 구현 로직을 갖지 않고 순수한 데이터를 표현하기 때문에 보통 속성과 게터/세터를 갖습니다.

 

코틀린에서는 DTO를 위해 데이터 클래스를 정의할 때 게터/세터/toString/equal 등을 직접 구현할 필요 없이 자동으로 구현해 줍니다. 코틀린의 데이터 클래스 내부에선 다음과 같은 메서드를 자동으로 생성해 줍니다.

 

  • 프로퍼티를 위한 게터/세터
  • 비교를 위한 equals()
  • 키 사용을 위한 hashCode()
  • 프로퍼티를 문자열로 변환해 순서대로 보여주는 toString()
  • 객체 복사를 위한 copy()
  • 프로퍼티에 상응하는 component1, component2 등

DTO를 통해 일종의 표준과 같은 약속을 정하면 송신측과 수신 측 모두 데이터를 쉽게 다룰 수 있어 DTO를 사용합니다.

 

 

2. 데이터 클래스 선언 방법

 

데이터 클래스는 data라는 선언자를 이용해서 선언합니다.

데이터 클래스는 다음과 같은 조건을 만족해야 합니다.

  • 주 생성자는 하나 이상의 매개변수를 가져야 합니다.
  • 주 생성자의 모든 매개변수는 var 혹은 val로 지정된 프로퍼티여야 한다.
  • 데이터 클래스는 abstract, open, sealed, inner 키워드를 사용할 수 없다.

단, 필요하다면 부 생성자나 init을 사용해 간단한 로직을 포함할 수 있습니다.

 

다음 예시를 통해 DTO에 대해 알아보겠습니다.

 

data class Customer(var name: String, var email: String){
    var job: String = "Unknown"
    constructor(name: String, email: String, _job: String): this(name, email){ job = _job }
    init { /** Simple logic here. */ }
}
fun main() {
    val cus1 = Customer("smoh", "smoh@mail.com")
    val cus2 = Customer("smoh", "smoh@mail.com")
    println(cus1 == cus2)
    println(cus1.equals(cus2))
    println("${cus1.hashCode()}, ${cus2.hashCode()}")
    println(cus1.toString())
}

 

  • var name: Stirng, var email: String: 주 생성자를 통해 두 프로퍼티를 갖습니다.
  • constructor: 부 생성자를 통해 job 프로퍼티를 하나 더 갖습니다.
  • init: init에 간단한 로직을 포함하게 할 수 있습니다.
  • 이 외에도 코틀린은 자동으로 여러 메서드를 생성해 둡니다.

위의 코드를 수행하면 다음과 같은 결과를 확인할 수 있습니다.

위 처럼 우리가 직접 정의하지 않은 여러 메서드를 코틀린에서 자동으로 추가해주며 바로 사용할 수 있습니다

 

 

 

3. 객체 디스트럭처링.

 

디스트럭처링(Destructuring)은 객체가 갖고 있는 프로퍼티를 개별 변수로 분해하여 할당하는 것을 말합니다.

js의...(Spread syntax)의 구조 분해 할당과 같은 개념으로 보입니다.

 

다음 예시를 통해 디스트럭처링에 대해 알아보겠습니다.

 

data class Customer(var name: String, var email: String){
var job: String = "Unknown"
constructor(name: String, email: String, _job: String): this(name, email){ job = _job }
init { /** Simple logic here. */ }
}
fun myFunc(): Customer { return Customer("smoh92", "smoh92@mail.com") }
fun main() {
    val cus1 = Customer("smoh1", "smoh1@mail.com")
    val (name, email) = cus1
    println("name = $name, email = $email")

    val (_, email2) = cus1

    val name3 = cus1.component1()
    val email3 = cus1.component2()
    println("name = $name3, email = $email3")

    val cus2 = Customer("smoh2", "smoh2@mail.com")
    val customers = listOf(cus1, cus2)
    for((name, email) in customers){ println("name = $name, email = $email") }

    val(myName, myEmail) = myFunc()

    val myLamda = {
        (nameLa, emailLa): Customer ->
        println(nameLa)
        println(emailLa)
    }
    myLamda(cus1)
}

 

  • val (name, email) = cus1: 기본적인 디스트럭처링
  • val (_, email2) = cus1: 디스트럭처링 하지 않을 프로퍼티는 언더바로 표시합니다.
  • val name3 = cus1.component1(): 컴포넌트 순서대로 골라서 디스트럭처링 하는 방법입니다.
  • for((name, email) in customers): 디스트럭처링 해야할 대상이 많은 경우 루프 문을 이용할 수 있습니다.
  • val(myName, myEmail) = myFunc(): 리턴 값이 객체인 함수에 대해서도 디스트럭처링을 적용할 수 있습니다.
  • val myLamda: 람다식을 사용해 디스트럭처링 하는 방법입니다.

해당 예시코드를 수행하면 다음과 같은 결과를 확인할 수 있습니다.

 

 

 

 

 

 

반응형

'Programming' 카테고리의 다른 글

[Kotlin] 34. 봉인 클래스와 열거형 클래스  (0) 2019.09.16
[Kotlin] 33. 내부 클래스  (0) 2019.09.16
[Kotlin] 31. 인터페이스  (0) 2019.09.12
[Kotlin] 30. 추상 클래스  (0) 2019.09.05
[Kotlin] 29. 컴패니언 객체  (0) 2019.09.01

+ Recent posts