doohong's blog

Study & Development


  • 홈

  • About

  • 태그

  • 카테고리

  • 아카이브

[gRPC]gRPC-1.개념

작성일 2019-12-07 | In gRPC | 댓글:

gRPC란

gRPC는 구글이 최초로 개발한 오픈 소스 원격 프로시저 호출(RPC) 시스템 입니다. 전송을 위해 HTTP/2를 사용하며 인터페이스 정의 언어로 프로토콜 버퍼를 사용하며 인증, 양방향 스트리밍 및 흐름 제어, 차단 및 비차단 바인딩, 취소 및 타임아웃 등의 기능을 제공 합니다.

프로토콜 버파란

프로토콜 버퍼(protocol Buffer)란 직렬화 데이터 구조입니다. (XML,JSON 와 비슷한)

프로토콜 버퍼는 같은 데이터를 보내더라도 크기가 작기 떄문에 동일 시간에 더 많은 데이터를 보낼 수 있으며 별도의 파싱이 필요 없게 됩니다.
하지만 JSON 구조는 사람이 읽기 편한 반면에 프로토콜 버퍼는 사람이 읽기 어려우며 proto 문법을 배워야 하는 단점도 존재 합니다.

protocol buffer 문법

protocol buffer 형태

1
2
3
4
5
6
7
8
9
10
11
12
13
14
yntax = "proto3";
package PB.Simple;
option java_package = "com.model.protobuf";

message SimpleProtoBufMessage {
int32 id = 1;
string message = 2;
enum MessageType {
PING = 0;
REQUEST = 1;
RESPONSE = 2;
}
MessageType messageType = 3;
}

syntax 는 컴파일할 대상 protobuf 버전을 지칭하며 java_package 와 같은 것들은 option 으로 지정되어 자바로 컴파일 시에만 적용됩니다.
위의 message 는 클래스로 매핑이 되며 그 안의 멤버변수들은 1, 2, 3 과 같은 연속된 숫자가 값으로 할당되는데 이는 직렬화 순서를 의미합니다.

기본 자료형

  • double(double)
  • float(float)
  • int32(int)
  • int64(long)
  • uint32(int)
  • uint64(long)
  • sint32(int)
  • sint64(long)
  • fixed32(int)
  • fixed64(long)
  • sfixed32(int)
  • sfixed64(long)
  • bool(bool)
  • string(String)
  • byte(ByteString)

default 값

  • string -> “”
  • bytes -> “”
  • bool -> false
  • numeric -> 0
  • enums -> 첫번 째 enum 값

enums type

option allow_alias = true;를 설정하면 서로 다른 필드에 대해서 같은 태그 번호(1)를 줄 수 있다.

설정하지 않으면 서로 다른 필드에 같은 태그 번호를 붙일 수 없다.

enum 값은 32비트 정수 범위여야만 한다. (varint encoding을 사용해서 비효율적이란다.)

message type안에 enum을 정의해도 된다. 정의한 enum은 .proto파일의 모든 message type에서 접근 가능하다.

필드 번호 지정 룰

필드 번호를 지정할 때는 1번에서 15번까지는 1바이트를 사용하고 16번부터 2047번 까지는 2바이트를 사용한다. 따라서 자주 발생하는 메세지의 필드 번호는 1~15를 매기는 것이 성능, 데이터 크기에 유리하다)
필드 번호 최소 - 1, 최대 2^29-1(536,870,911)
단, 19000~19999번은 예약된 번호라 사용하면 안된다.
singular필드는 0~1, repeated필드는 0~N개가 있다.

수식어

required, optional, repeated는 modifier(수식어)라고 하는데, 해당 필드가 반드시 필요한지와 선택인지 또는 반복되는지를 나타내기 위해 사용합니다.

required 는 proto3에서 없어졌고, optional 은 proto3에서 기본형이라 역시 사라졌습니다.

[Kotlin]코틀린 기본 개념 정리-1.apply, also, let, run, with

작성일 2019-11-07 | In Kotlin | 댓글:

코틀린의 apply, also, let, run, with

메소드 정의

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// apply
inline fun <T> T.apply(block: T.() -> Unit): T {
block()
return this
}
// also
inline fun <T> T.also(block: (T) -> Unit): T {
block(this)
return this
}
// let
inline fun <T, R> T.let(block: (T) -> R): R {
return block(this)
}
// run
inline fun <T, R> T.run(block: T.() -> R): R {
return block()
}
// with
inline fun <T, R> with(receiver: T, block: T.() -> R): R {
return receiver.block()
}

with, also, apply, let, run 은 아래의 3 가지 차이점 중 1 가지가 서로 다릅니다.

  • 범위 지정 함수 의 호출시에 수신 객체가 매개 변수로 명시적으로 전달되거나 수신 객체의 확장 함수로 암시적 수신 객체 로 전달된다.
  • 범위 지정 함수 의 수신 객체 지정 람다 에 전달되는 수신 객체가 명시적 매개 변수 로 전달 되거나 수신 객체의 확장 함수로 암시적 수신 객체로 코드 블록 내부로 전달 된다.
  • 범위 지정 함수의 결과로 수신 객체를 그대로 반환하거나 수신 객체 지정 람다 의 실행 결과를 반환한다.

각 메서드 설명

apply

수신 객체 람다 내부에서 수신 객체의 함수를 사용하지 않고 수신 객체 자신을 다시 반환 하려는 경우에 apply 를 사용합니다.
수신 객체 의 프로퍼티 만을 사용하는 대표적인 경우가 객체의 초기화 이며, 이곳에 apply 를 사용합니다.

also

수신 객체 람다가 전달된 수신 객체를 전혀 사용 하지 않거나 수신 객체의 속성을 변경하지 않고 사용하는 경우 also 를 사용합니다.
also 는 apply 와 마찬가지로 수신 객체를 반환 하므로 블록 함수가 다른 값을 반환 해야하는 경우에는 also 를 사용할수 없습니다.
예를 들자면, 객체의 사이드 이팩트를 확인하거나 수신 객체의 프로퍼티에 데이터를 할당하기 전에 해당 데이터의 유효성을 검사 할 때 매우 유용합니다.

let

수신 객체의 객체를 블록의 인자로 넘기고 블록의 결과값을 반환합니다.
null 체크 후 코드를 실행하거나 블록 내의 결과물을 반환하고 싶을경우,
단일 지역 변수의 범위를 제한하고 싶을 경우 사용됩니다.

run

어떤 값을 계산할 필요가 있거나 여러개의 지역 변수의 범위를 제한하려면 run 을 사용합니다.
매개 변수로 전달된 명시적 수신객체 를 암시적 수신 객체로 변환 할때 run ()을 사용할수 있습니다.

with

안전한 호출(?.)을 지원하지 않고 Non-nullable (Null 이 될수 없는) 수신 객체 이고 결과가 필요하지 않은 경우에만 with 를 사용합니다.

[JAVA]디자인패턴-4.Singleton

작성일 2019-06-28 | In Design Pattern | 댓글:

Singleton 패턴

싱글톤 패턴이란 인스턴스를 하나만 만들어 사용하기 위한 패턴이다. 커넥션 풀, 스레드 풀, 디바이스 설정 객체 등의 경우, 인스턴스를 여러 개 만들게 되면 자원을 낭비하게 되거나 버그를 발생시킬 수 있으므로 오직 하나만 생성하고 그 인스턴스를 사용하도록 하는 것이 이 패턴의 목적이다.
하나의 인스턴스만을 유지하기 위해 인스턴스 생성에 특별한 제약을 걸어둬야 한다. new를 실행할 수 없도록 생성자에 private 접근 제어자를 지정하고, 유일한 단일 객체를 반환할 수 있도록 정적 메소드를 지원해야 한다. 또한 유일한 단일 객체를 참조할 정적 참조변수가 필요하다.

예제

1
2
3
4
5
6
7
8
public class Singleton {
private static Singleton singletonObject = new Singleton();
public static Singleton getInstance(){
return singletonObject;
}
private Singleton(){
}
}

클래스 로드시 new가 실행되고 하나의 인스턴스를 가지게 된다. 코드도 쉽고 성능도 나름 좋은 편이다.
하지만 이렇게 되면 이 인스턴스를 사용하지 않을 경우에도 객체가 프로그램이 실행되서부터 끝까지 메모리에 존재하게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
public class Singleton {
private static Singleton singletonObject;

private Singleton() {}

public static Singleton getInstance() {
if (singletonObject == null) {
singletonObject = new Singleton();
}
return singletonObject;
}
}

가장 기본적인 싱글톤 패턴이다.
클래스 로드시에 인스턴스가 생성되지 않고 getInstance 를 호출할 때 생성된다.
인스턴스를 사용할 필요가 없는 경우에는 생성되지 않는다는 장점이 있다.
하지만 멀티스레드 환경에서 동시에 접근하다 인스턴스가 두개가 생기는 문제가 발생할 여지가있다.

1
2
3
4
5
6
7
8
9
10
11
12
public class Singleton {
private static Singleton singletonObject;

private Singleton() {}

public static synchronized Singleton getInstance() {
if (singletonObject == null) {
singletonObject = new Singleton();
}
return singletonObject;
}
}

synchronized 키워드를 사용하여 동기화를 하였지만 성능상 문제가 있어 좋은 방법은 아니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Singleton {
private static volatile Singleton singletonObject;

private Singleton() {}

public static Singleton getInstance() {
if (singletonObject == null) {
synchronized (Singleton.class) {
if(singletonObject == null) {
singletonObject = new Singleton();
}
}
}
return singletonObject;
}
}

DCL(Double Checking Locking)을 써서 getSingletonObject()에서 동기화 되는 영역을 줄일 수 있다. 초기에 객체를 생성하지 않으면서도 동기화하는 부분을 작게 만들었다. 그러나 이 코드는 멀티코어 환경에서 동작할 때, 하나의 CPU를 제외하고는 다른 CPU가 lock이 걸리게 된다. 그렇기 때문에 다른 방법이 필요하다.

1
2
3
4
5
6
7
8
9
10
public class Singleton {
private Singleton(){
}
private static class SingletonHolder{
static final Singleton4 single = new Singleton4();
}
public static Singleton getInstatnce(){
return SingletonHolder.single;
}
}

마지막 방법은 내부 클래스를 이용하는 방법이다. 내부 클래스가 호출되는 시점에 최초로 생성이 되기 때문에 필요하지 않을때 생성하지 않을 수 있으며 속도도 빠르다.

ssl 적용- webroot방식(with nginx)

작성일 2019-06-22 | Edited on 2019-06-24 | In etc | 댓글:

ssl 적용 - webroot방식(with nginx)

환경

OS : CentOS7

WebServer : Nginx

사용법

  1. 사용할 webroot 폴더를 만들어 주고 html파일을 넣어준다 (예제는 test)

예제처럼 도메인에 맞춰 폴더를 만들어주면 좋을듯

$ mkdir /opt/test 

$ nano /opt/test/index.html
  1. /etc/nginx/conf.d 에 test.conf파일을 만들어 준다.

www. 같은 도메인은 server_name에 엔터단위로 구분

location에 webroot와 실행시킬 html파일 입력

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#
# The default server
#
server {
listen 80;
server_name test.com www.test.com;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /opt/test;
index index.html;
}
error_page 404 /404.html;
location = /404.html {
root /usr/share/nginx/html;
}
}

  1. Certbot 설치

https://certbot.eff.org/ 홈페이지에서 각자 맞는 환경 선택

여기선 centos에 nginx로 진행

$ yum install certbot python-certbot-nginx
  1. centos에 명령어를 입력해준다.

test.com 뿐만아니라 www.test.com도 인증서를 적용시키기 위해 다음과 같은 옵션 추가

-d test.com -d www.test.com

$ certbot --webroot --installer nginx -w /opt/test -d test.com -d www.test.com

redirect 옵션을 선택하면 자동으로 conf파일을 변경시켜주는것 같다.

  1. /etc/nginx/conf.d에 test.conf
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    server {
    if ($host = www.test.com) {
    return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = test.com) {
    return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name test.com www.test.com;
    return 301 https://$host$request_uri;
    }
    srver {
    listen 443 ssl;
    server_name test.com www.test.com;
    ssl_certificate /etc/letsencrypt/live/test/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/test1/privkey.pem; # managed by Certbot
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout 10m;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    location / {
    root /opt/test;
    index index.html;
    try_files $uri$args $uri$args/ $uri $uri/ /index.html =404;
    }
    }

자동으로 변경안되면 위에처럼 http는 https로 리턴시켜죽로 443(ssl)포트는 생성된 키를 매칭시켜주면 된다.

  1. nginx reload

    $ systemctl reload nginx

  2. TEST

test.com 나 www.test.com로 접속해본다

https로 rewrite되고 정상적으로 인증이 되는지 확인

  1. Renew certificate with cron

Let’s Encrypt SSL인증서는 90일마다 갱신해줘야 한다.

$ /opt/certbot/certbot-auto renew --dry-run
or
$ certbot renew --dry-run

$ cerbot renew --force-renewal

–dry-run 옵션을 이용하여 잘동작하는지 확인할 수 있다.

–force-renewal 명령어를 이용하면 남은기간에 상관없이 갱신 받을 수 있다.

갱신하는 방법은 한줄로 가능하지만 크론탭을 이용하여 자동적으로 갱신되도록 하는게 좋다.

크론탭을 수정하려면 -e옵션을 사용하고 작성된 크론탭을 보려면 -l옵션을 이용한다

$ crontab -e

0 18 1 */1 * /opt/certbot/certbot-auto renew --dry-run

$ crontab -l

매달 1일 18시에 갱신을 하는 크론탭을 작성하고 -l 옵션을 이용해 확인한다.

$ certbot certificates //발급된 인증서 목록 확인 명령어

ssl 적용- webroot방식(with apache)

작성일 2019-06-22 | In etc | 댓글:

ssl 적용- webroot방식(with apache)

webroot방식이란

  1. Standalone 방식

    이 방법은 Certbot이 간이 웹 서버를 돌려 도메인 인증 요청을 처리하는 방식입니다.하지만 인증용 간이 서버가 80, 443번 포트를 사용하기 때문에 운영 중인 서버가 해당 포트를 쓰게 된다면, 발급 또는 갱신 시 마다 잠시 서버를 내려야 하는 문제가 있습니다.물론 해당 포트를 사용하지 않는다면 이 방법을 사용하셔도 무방합니다.

  2. Webroot 방식

    이 방법은 도메인 인증을 위해 외부에서 접근 가능한 경로를 제공하고, Let’s Encrypt 측에서 해당 경로로 접속해 인증을 하는 방식입니다.이 방식을 사용할 경우 1번 방식의 서비스 종료는 하지 않아도 됩니다.

서버를 내려야 하는 문제를 해결하기 위해 Webroot방식을 적용 시키려고 한다.

환경

OS : CentOS7

WebServer : Apache

사용법

  1. /var/www/html 에 사용할 VirtualHost 폴더와 그안에 html파일을 넣어준다 (예제는 test.com)

예제처럼 도메인에 맞춰 폴더를 만들어주면 좋을듯

$ mkdir /var/www/html/test 

$ nano /var/www/html/test/index.html
  1. /etc/httpd/conf.d 에 test.conf파일을 만들어 준다.

www. 같은 도메인은 ServerAlias 을 이용해 추가

RewriteCond %{SERVER_NAME} =www.test [OR] 을 이용해 https로 rewrite

1
2
3
4
5
6
7
8
9
10
11
12
<VirtualHost *:80>
ServerName test.com
ServerAlias www.test.com
DocumentRoot /var/www/html/test
CustomLog /var/log/httpd/access.log common
ErrorLog /var/log/httpd/error.log
RewriteEngine on
RewriteRule ^/.well-known/ - [L]
RewriteCond %{SERVER_NAME} =www.test.com [OR]
RewriteCond %{SERVER_NAME} =test.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
  1. Certbot 설치

https://certbot.eff.org/ 홈페이지에서 각자 맞는 환경 선택

여기선 centos에 apache로 진행

$ yum install certbot python-certbot-apache
  1. centos에 명령어를 입력해준다.

test.com 뿐만아니라 www.test.com도 인증서를 적용시키기 위해 다음과 같은 옵션 추가

-d test.com -d www.test.com

$ certbot --webroot --installer apache -w /var/www/html/test -d test.com -d www.test.com
  1. /etc/httpd/conf.d에 gajah.tours-le-ssl.conf 파일이 생성됨 내용은

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <IfModule mod_ssl.c>
    <VirtualHost *:443>
    ServerName test.com
    ServerAlias www.test.com
    DocumentRoot /var/www/html/test
    CustomLog /var/log/httpd/access.log common
    ErrorLog /var/log/httpd/error.log
    RewriteEngine on
    RewriteRule ^/.well-known/ - [L]
    # Some rewrite rules in this file were disabled on your HTTPS site,
    # because they have the potential to create redirection loops.

    # RewriteCond %{SERVER_NAME} =www.test.com [OR]
    # RewriteCond %{SERVER_NAME} =test.com
    # RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
    Include /etc/letsencrypt/options-ssl-apache.conf
    SSLCertificateFile /etc/letsencrypt/live/test/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/test/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/test/chain.pem
    </VirtualHost>
    </IfModule>
  2. apache 재시작

    $ systemctl restart httpd

  3. TEST

test.com 나 www.test.com 로 접속해본다

https://test.com 로 rewrite되고 정상적으로 인증이 되는지 확인

  1. Renew certificate with cron

Let’s Encrypt SSL인증서는 90일마다 갱신해줘야 한다.

$ /opt/certbot/certbot-auto renew --dry-run
or
$ certbot renew --dry-run

—dry-run 옵션을 이용하여 잘동작하는지 확인할 수 있다.

갱신하는 방법은 한줄로 가능하지만 크론탭을 이용하여 자동적으로 갱신되도록 하는게 좋다.

크론탭을 수정하려면 -e옵션을 사용하고 작성된 크론탭을 보려면 -l옵션을 이용한다

$ crontab -e

0 18 1 */1 * /opt/certbot/certbot-auto renew --dry-run

$ crontab -l

매달 1일 18시에 갱신을 하는 크론탭을 작성하고 -l 옵션을 이용해 확인한다.

[JAVA]디자인패턴-1.Iterator

작성일 2019-06-01 | In Design Pattern | 댓글:

iterator 패턴은

자바 프로그래밍을 하다 보면 Array, Set, Map, List 과 같은 자료구조를 많이 사용하게 된다.
이 자료구조의 특징들은 어떠한 데이터들의 집합체라는 것이다. 그래서 집합체들을 다룰 때는 얘들이 가지고 있는 개별 원소에 대해서 이런 저런 작업들을 할 일이 많다.
iterator를 쓰게 되면, 집합체와 개별 원소들간에 분리시켜 생각할 수가 있다.
심지어는 그 집합체가 어떤 클래스의 인스턴스인지 조차 신경쓰지 않아도 된다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class MagicianList implements Iterable<String> {
private List<String> list = new ArrayList<String>();

public void add(String name){
list.add(name);
}

public Iterator<String> iterator() {
return new Iterator<String>(){
int seq = 0;
public boolean hasNext() {
return seq < list.size();
}
public String next() {
return list.get(seq++);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}


public static void main(String[] arg){
MagicianList magicians = new MagicianList();
magicians.add("이은결");
magicians.add("Kevin parker");
magicians.add("David Blaine");

Iterator<String> iterator = magicians.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println(element);
}
}
}

magicians 의 원소들을 뽑아내는데, magicians 라는 변수를 전혀 쓰지 않는다.
물론, 내부적으로 iterator라는 변수가 magicians와 관계를 유지해주고 있긴 하지만 일단 iterator를 가지고 온 후에는 데이터 집합체가 뭐냐에 신경을 쓸 필요가 없어진 것이다.
iterator만 가져오면, hasNext() , next() 만 가지고 반복하면서 원소들에 대해서 처리를 하면 된다.

Iterator관련 interface

Iteraable 인터페이스를 보게되면 Iterator iterator() 라는 메소드 한개만 가지고 있다.
그리고 이 iterator 메소드를 이용하여 만들어진 iterator클래스는 클래스는 3개의 메서드를 가지고 있다.
hasNext()는 다음 구성 요소가 있냐고 물어보는 메서드이다. next()는 그 요소를 뽑아 온다.
remove()는 일부러 구현을 안하였다.
API에 보면, 마지막으로 꺼낸 요소를 제거한다.(optional operation) 이라고 되어있는데 optional이라는 걸 강조하기위해 구현을 하지 않았다.
요기서 한가지 짚고 넘어가야 할 것은 시퀀스는 hasNext()가 아니라 next()에서 증가시켜야 한다는 것이다.
hasNext()를 호출하고 또 호출하는 일이 발생할 수도 있기 때문이다. hasNext라는 메소드 이름이, next를 가지고 있는지를 체크하겠다는 것이기 때문이다.

JAVA API에 있는 Iterator

우리가 알고 있는 일반적인 집합체들은 전부 Iterator를 제공한다.
Set, List 등은 Collection 을 상속 받는데, Collection이 Iteratable을 상속 받기 때문이다.
위에서 만든 클래스처럼 리스트같은 Collection을 사용할땐 list.iterator()를 사용하여 각 컬렉션의 iterator를 뽑아올 수 있다.

Map은 왜 Iterator를 제공하지 않는 지를 살펴보자.
Map은 Set이나 List와는 달리 key-value의 구조이다. key에 대한 Iterator인지 value에 대한 Iterator인지 구별할 방법이 없다. 그래서 아예 제공을 하지 않는다.
그러나 Map에는 key에 대해서는 Set keySet()이라는 key를 Set으로 가져오기를 지원하고, value에 대해서는 Collection values() 를 제공한다. 위에서 말한것 처럼 Set과 Collection은 둘다 Iterator를 제공한다.

[JAVA]디자인패턴-1.Adapter

작성일 2019-06-01 | Edited on 2019-06-02 | In Design Pattern | 댓글:

Adapter 패턴

한 클래스의 인터페이스를 클라이언트에서 사용하고자하는 다른 인터페이스로 변환한다.

어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class IteratorToEnumeration implements Enumeration<String>{
private Iterator<String> iter;
public IteratorToEnumeration(Iterator<String> iter) {
this.iter = iter;
}
public boolean hasMoreElements() {
return iter.hasNext();
}
public String nextElement() {
return iter.next();
}
}

---------------뭔가 훌륭한 method를 가지고 있는 클래스 ------------

public class Test {
public static void goodMethod(Enumeration<String> enu){
while (enu.hasMoreElements()) {
System.out.println(enu.nextElement());
}
}

public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("이은결");
list.add("Kevin parker");
list.add("David Blaine");
Enumeration<String> ite = new IteratorToEnumeration(list.iterator());
Test.goodMethod(ite);
}
}

최종족으로 사용하고자 하는 메서드는 goodMethod()이다.
하지만 iterator을 가지고 있는 List는 Enumeration 인자가 없기 때문에 사용하지 못한다.
이때 IteratorToEnumeration 클래스가 iterator를 받아서 Enumeration 클래스를 사용 할 수 있도록 Enumeration 인터페이스의 메서드를 구현 한다.

AtoB의 형태를 가지는 Adapter는 A를 멤버변수로 가지고 B를 구현한다.

Adapter를 구현하는 방법

위에서 소개된 방법은 “구성을 통한 방법” 또는 “위임을 통한 방법” 이다. Adapter 자체는 하는 일이 별로 없다. 내부적으로 멤버한테다가 일을 다 떠넘긴다. 외관상 다른 형태로 변환가능하기 위한 것이지 어떤 일을 직접할려는 것은 아니다.

두번째 방법은 상속을 이용하는 방법이다. A to B로 할 경우 A와 B를 둘다 구현하는 방법이다. A와 B가 둘 다 인터페이스거나, 하나만 인터페이스일 때는 가능하지만, 둘 다 클래스일 경우에는 불가능하다.

세번째 방법은 Adapter 클래스를 만들지 않고 method로 만드는 방법이다.

1
2
3
4
5
6
7
8
9
10
11
public static Enumeration<String> iteratorToEnumeration(final Iterator<String> iter) {
return new Enumeration<String>() {
public boolean hasMoreElements() {
return iter.hasNext();
}

public String nextElement() {
return iter.next();
}
};
}

눈치 빠른 사람들은 인자가 final이란 것을 봤을 것이다. final로 말뚝 박는 건 “변경 절대 불가!” 를 보장하는 것이다. 메서드 안에서 Enumeration의 구현체가 인자로 받은 것을 사용하는데, 이런 경우에는 인자가 final 로 정의되어야 하며, 그렇지 않을 경우 컴파일시에 문제가 된다.
final로 정의한다는 것은 read-only라는 뜻이다. 주의할 것은 read-only라는 게 다른 변수로 할당을 못한다는 것 뿐 내부의 메서드를 호출하지 못한다는 것은 아니다. (메서드 내부에서 iter = 다른것; 이런식으로 사용하지 못한다는 이야기다.)

세번째 방법은 Adapter 패턴이라고 불리지는 않는다. 그러나 하는 일이 비슷하다.

[JAVA]디자인패턴-3.Factory

작성일 2019-06-01 | Edited on 2019-06-04 | In Design Pattern | 댓글:

Factory Method패턴

factory는 객체를 찍어내는 공장으로 생각하면 된다.
객체 선언은 보통 new 객체() 이렇게 하지만 factory는 내부에서 그런 일을 해준다.
즉 factory를 가져다가 쓰는 부분에서는 new 객체()와 같은 식으로 변수를 선언할 필요가 없다.
객체를 만들어내는 부분을 서브 클래스Sub-Class에 위임하는 패턴.
즉, new 키워드를 호출하는 부분을 서브 클래스에 위임하는 것이다.
결국 팩토리 메소드 패턴은 객체를 만들어내는 공장(Factory 객체)을 만드는 패턴이라 이해하면 된다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public interface Animal {
public void printDescription();
}
public class AnimalFactory {
public static Animal create(String animalName){
if (animalName == null) {
throw new IllegalArgumentException("null은 안 되지롱~");
}
if (animalName.equals("소")) {
return new Cow();
}else if (animalName.equals("고양이")) {
return new Cat();
}else if (animalName.equals("개")) {
return new Dog();
}else{
return null;
}
}
}

public class Cat implements Animal {
public void printDescription() {
System.out.println("쥐잡기 선수");
}
}
public class Cow implements Animal {
public void printDescription() {
System.out.println("우유 및 고기 제공");
}
}
public class Dog implements Animal {
public void printDescription() {
System.out.println("주로 집 지킴");
}
}
public class Test {
public static void main(String[] args) {
Animal a1= AnimalFactory.create("소");
a1.printDescription();
Animal a2= AnimalFactory.create("고양이");
a2.printDescription();
Animal a3= AnimalFactory.create("개");
a3.printDescription();
}
}

일단 Animal이라는 인터페이스가 있고 Cat, Cow, Dog 이라는 인터페이스의 구현체들이 있다..
그리고 AnimalFactory가 있는데, 여기서 Animal의 구현체를 돌려준다.
Test에서 new Cow()와 같이 하지 않고, AnimalFactory.create(“소”)를 호출하는 게 일반적인 방법과의 차이다.

Factory 의 유용성

Animal a1 = AnimalFactory.create(“소”); 와 같은 코드에서 a1이 Cow라는 것을 굳이 신경쓰지 않겠다는 것이다. Test클래스 안에는 new 라는 구문 자체가 없다.
정확히 어떤 클래스의 인스턴스인지 신경쓰지 않고 구현할 수 있는 장점이 있다. 객체 타입이 굉장히 유연해 질 수 있다는 뜻이다.
팩토리 메소드 패턴을 사용하는 이유는 클래스간의 결합도를 낮추기 위한 것이다. 결합도라는 것은 간단히 말해 클래스의 변경점이 생겼을 때 얼마나 다른 클래스에도 영향을 주는가를 뜻하는데, 팩토리 메소드 패턴을 사용하는 경우 직접 객체를 생성해 사용하는 것을 방지하고 서브 클래스에 위임함으로써 보다 효율적인 코드 제어를 할 수 있고 의존성을 제거한다. 결과적으로 결합도 또한 낮출 수 있게 된다.

Factory Method의 종류

예제에서는 Factory의 인스턴스를 만들지 않고, static 메쏘드인 create()만을 호출 하였다. 이런 방식을 static factory method라고 한다.
그냥 factory method라고 하면, factory의 인스턴스를 만들어서 쓰는 방식을 말한다.
static factory에 비해 사용 빈도는 좀 떨어지지만, factory의 인스턴스에 귀속되는 객체를 생성해야 할 때는 이런 방식을 사용한다.

[JAVA]자바의 기본 개념 정리-9.Checked,Unchecked Exception

작성일 2019-05-30 | In JAVA | 댓글:

Exception Error

Exception은 주로 자바에서 제공하는 java.lang.Exception 클래스와 Exception 클래스의 서브클래스들이 쓰이는 상황을 말한다.

예외(Exception)는 체크 예외(Checked Exception)와 언체크 예외(Unchecked Exception), 두 가지로 나눌 수 있다. 언체크 예외는 RuntimeException을 상속한 것들을 말하고, 체크 예외는 이외의 예외들을 말한다. 물론, RuntimeException 또한 Exception 클래스의 서브 클래스이지만, 프로그램이 동작하는 상황에서 발생하는 예외를 처리한다는 점에서 조금 특별하게 취급한다.

오류(Error)는 시스템에 비정상적인 상황이 생겼을 때 발생한다. 이는 시스템 레벨에서 발생하기 때문에 심각한 수준의 오류이다. 따라서 개발자가 미리 예측하여 처리할 수 없기 때문에, 애플리케이션에서 오류에 대한 처리를 신경 쓰지 않아도 된다.

오류가 시스템 레벨에서 발생한다면, 예외(Exception)는 개발자가 구현한 로직에서 발생한다. 즉, 예외는 발생할 상황을 미리 예측하여 처리할 수 있다. 즉, 예외는 개발자가 처리할 수 있기 때문에 예외를 구분하고 그에 따른 처리 방법을 명확히 알고 적용하는 것이 중요하다.
java_ExceptionError

Checked Exception과 Unchecked(Runtime) Exception

java_ExceptionError

Checked Exception 과 Unchecked Exception의 가장 큰 차이는 ‘꼭 처리를 해야 하냐’ 이다.

Checked Exception이 발생할 가능성이 있는 메소드라면 반드시 로직을 try/catch로 감싸거나 throw로 던져서 처리해야 한다.

Unchecked Exception은 명시적인 예외처리를 하지 않아도 된다. 이 예외는 피할 수 있지만 개발자가 부주의해서 발생하는 경우가 대부분이고, 미리 예측하지 못했던 상황에서 발생하는 예외가 아니기 때문에 굳이 로직으로 처리를 할 필요가 없도록 만들어져 있다.

그리고 한 가지 더 인지하고 있으면 좋은 것이 있다. 바로 예외발생시 트랜잭션의 roll-back 여부이다. 기본적으로 Checked Exception은 예외가 발생하면 트랜잭션을 roll-back하지 않고 예외를 던져준다. 하지만 Unchecked Exception은 예외 발생 시 트랜잭션을 roll-back한다는 점에서 차이가 있다. 트랜잭션의 전파방식 즉, 어떻게 묶어놓느냐에 따라서 Checked Exception이냐 Unchecked Exception이냐의 영향도가 크다. roll-back이 되는 범위가 달라지기 때문에 개발자가 이를 인지하지 못하면, 실행결과가 맞지 않거나 예상치 못한 예외가 발생할 수 있다. 그러므로 이를 인지하고 트랜잭션을 적용시킬 때 전파방식(propagation behavior)과 롤백규칙 등을 적절히 사용하면 더욱 효율적인 애플리케이션을 구현할 수 있을 것이다.

전략

같은 작업이 진행 되더라도 발생하는 Exception에 따라 작업이 rollback(Unchecked Exception이) 될 수도 있고 commit(Checked Exception이)까지 완료될 수가 있다.

기본적으로 Checked Exception는 복구가 가능하다는 메커니즘을 가지고 있다. 그렇기 때문에 Rollback을 진행하지 않는다 생각한다.

하지만 Checked Exception 예외가 발생했을 경우 복구 전략을 갖고 그것을 복구할 수 있는 경우는 적다.

따라서 복구할 수 없는 경우나 rollback을 시켜줘야 하는 경우 더욱더 구체적인 Unchecked Exception를 만들어 발생 시켜주는 것이 더욱 좋은 처리 방법이라 생각한다.

[JAVA]자바의 기본 개념 정리-8.JDK 7과 8의 정리

작성일 2019-05-20 | Edited on 2019-05-25 | In JAVA | 댓글:

Java JDK 7과 8의 정리

JDK 7

Type Inference

JDK 7 이전

1
2
Map<String, List<String>> employeeRecords = new HashMap<String, List<String>>();
List<Integer> primes = new ArrayList<Integer>();

JDK 7 이후

1
2
Map<String, List<String>> employeeRecords = new HashMap<>();
List<Integer> primes = new ArrayList<>();

String in Switch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
switch (day) {
case "NEW":
System.out.println("Order is in NEW state");
break;
case "CANCELED":
System.out.println("Order is Cancelled");
break;
case "REPLACE":
System.out.println("Order is replaced successfully");
break;
case "FILLED":
System.out.println("Order is filled");
break;
default:
System.out.println("Invalid");
}

Automatic Resource Management

JDK 7 이전

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    FileInputStream fin = null;
BufferedReader br = null;
try {
fin = new FileInputStream("info.xml");
br = new BufferedReader(new InputStreamReader(fin));
if (br.ready()) {
String line1 = br.readLine();
System.out.println(line1);
}
} catch (FileNotFoundException ex) {
System.out.println("Info.xml is not found");
} catch (IOException ex) {
System.out.println("Can't read the file");
} finally {
try {
if (fin != null)
fin.close();
if (br != null)
br.close();
} catch (IOException ie) {
System.out.println("Failed to close files");
}
}
}

JDK 7 이후

1
2
3
4
5
6
7
8
9
10
11
12
try (FileInputStream fin = new FileInputStream("info.xml");
BufferedReader br = new BufferedReader(new InputStreamReader(
fin));) {
if (br.ready()) {
String line1 = br.readLine();
System.out.println(line1);
}
} catch (FileNotFoundException ex) {
System.out.println("Info.xml is not found");
} catch (IOException ex) {
System.out.println("Can't read the file");
}

Underscore in Numeric literal

1
2
3
4
5
int billion = 1_000_000_000; // 10^9
long creditCardNumber = 1234_4567_8901_2345L; //16 digit number
long ssn = 777_99_8888L;
double pi = 3.1415_9265;
float pif = 3.14_15_92_65f;

JDK 8

Lambda expressions

람다 표현식은 Anonymous Function라고 할 수 있다
람다를 이용하여 코드를 간결하게 할 수 있다

1
2
3
4
5
6
7
8
9
10
11
// Before
Runnable oldRunner = new Runnable(){
public void run(){
System.out.println("I am running");
}
};

// After
Runnable java8Runner = () -> {
System.out.println("I am running");
};

Method Reference

특정 람다 표현식을 축약한 것으로 볼 수 있다
메서드 정의를 활용하여 람다처럼 사용 가능하다

1
2
3
4
5
6
7
8
9
10
11
12
// Before  
inventory.sort((Apple a1, Apple a2) ->
a1.getWeight().compareTo(a2.getWeight()));

// After
inventory.sort(comparing(Apple::getWeight));

/*
Lamda -> Method Reference
(Apple a) -> a.getWeight Apple::getWeight
() -> Thread.currentThread().dumpStack() Thread.currentThread()::dumpStack
*/

Stream

간결하게 컬렉션의 데이터를 처리하는 기능

1
2
3
4
5
6
7
8
9
10
// Before 
List<Shape> list = new ArrayList<Shape>();
for (Shape s : shapes) {
if (s.getColor() == RED) {
list.add(s);
}
}

// After
shapes.stream().filter(s -> s.getColor() == Red).collect(toList());

Default Method

인터페이스의 구현체를 인터페이스 자체에서 기본으로 제공 가능하다
구현 클래스에서 인터페이스를 구현하지 않아도 된다

1
2
3
4
5
6
7
public interface Sized {
int size();

default boolean isEmpty() { // Default Method
return size() == 0;
}
}

Optional

값을 Optional로 캡슐화하여 NullPointerException을 막는다
값이 존재한다면 Optional 클래스는 값을 감싼다
값이 없다면 Optional.empty메서드로 Optional을 리턴한다

New date / time APIs

  • Joda-Time의 많은 기능을 java.time 패키지로 추가했다
    • LocalDate, LocalTime, Instant, Duration, Period …
12…6
박주홍

박주홍

53 포스트
11 카테고리
112 태그
GitHub E-Mail FB Page Instagram
© 2019 박주홍
Powered by Hexo v3.8.0
|
Theme – NexT.Muse v6.7.0