Get values using destructuring assignment.


Environment and Prerequisite

  • Javascript


Destructuring Assignment

Definition

  • Destructuring assignment: It is an syntax which can unpack values from elements of array or properties in object.
  • There are many examples on link in below ‘Reference’


Simple Examples

Array Destructuring

let arr = [1, 2, 3, 4, 5];
let [a, b, ...c] = arr;

console.log(arr);
console.log(a);
console.log(b);
console.log(c);
[ 1, 2, 3, 4, 5 ]
1
2
[ 3, 4, 5 ]

Object Destructuring

let object = {
  a: 1,
  b: "test",
  c: [1, 2],
  d: { name: "test", age: 28 },
};

// Key must be same
let { a, b, c, d } = object;

/* Assign to different variable name example
let { a: e, b: f, c: g, d: h } = object;
*/

console.log(a);
console.log(b);
console.log(c);
console.log(d);
1
test
[ 1, 2 ]
{ name: 'test', age: 28 }


Usage

  • By using this destructuring assignment, we can return multi values from function. Technically, its function return object or array and receives its values in caller using destructuring assignment.

Array Destructuring Example

function test() {
  return [1, 2, 3, 4, 5];
}

let [a, b, ...c] = test();

console.log(a);
console.log(b);
console.log(c);
1
2
[ 3, 4, 5 ]

Object Destructuring Example

function test() {
  let object = {
    a: 1,
    b: "test",
    c: [1, 2],
    d: { name: "test", age: 28 },
  };

  return object;
}

let { a, b, c, d } = test();

console.log(a);
console.log(b);
console.log(c);
console.log(d);
1
test
[ 1, 2 ]
{ name: 'test', age: 28 }


Reference

Jekyll Liquid 템플릿에서 배열을 만들고 원소를 추가하는 방법을 알아보자


환경

  • Linux
  • Jekyll


Jekyll 배열 생성 및 추가

생성

  • split 필터 사용
  • 문자열을 ,로 구분해 배열로 만드는 필터로 문자열이 없기 때문에 빈 배열을 만듭니다.
{% assign ARRAY_NAME = "" | split: ',' %}


추가

  • push 사용해 배열에 추가하고 추가한 배열을 변수에 다시 할당합니다.
  • push를 하면 현재 배열에 추가된채로 저장되는게 아니기 때문에 새로 할당해야 합니다.
{% assign ARRAY_NAME = ARRAY_NAME | push: ELEMENT %}


예제

  • 아래는 블로그에서 특정 collections를 가져와서 새로 배열을 만드는 예시
  • opensource-contributions: 배열
  • post: 원소
{% assign opensource-contributions = "" | split: ',' %}
{% for post in site.opensource-contributions %}
  {% if post.post_id != page.post_id %}
     {% assign opensource-contributions = opensource-contributions | push: post %}
  {% endif %}
{% endfor %}


참고자료

Summarize making array and adding element in Jekyll Liquid


Environment and Prerequisite

  • Linux
  • Jekyll


Jekyll Array Create and Add

Create

  • Use split filter
  • It is used to convert comma-separated items from a string to an array but there is no string so it makes empty array.
{% assign ARRAY_NAME = "" | split: ',' %}


Add

  • Use push to add element to array and reassign to original variable.
  • push does not actually add to current array so it needs to be reassigned.
{% assign ARRAY_NAME = ARRAY_NAME | push: ELEMENT %}


Example

  • Example of making new array from specific collections in my blog.
  • opensource-contributions: Array
  • post: Element
{% assign opensource-contributions = "" | split: ',' %}
{% for post in site.opensource-contributions %}
  {% if post.post_id != page.post_id %}
     {% assign opensource-contributions = opensource-contributions | push: post %}
  {% endif %}
{% endfor %}


Reference

업데이트(2020.07.18): 예제 및 코드 변경

싱글턴 패턴(Singleton Pattern)에 대해서 알아보자


환경

  • Java


싱글턴 패턴(Singleton Pattern)이란?

싱글턴 패턴(Singleton Pattern)

  • 싱글턴 패턴(Singleton Pattern): 클래스가 오직 하나의 인스턴스만을 유지하도록 하는 패턴이며 한번 만들어지면 getInstance()와 같은 함수 또는 메소드 호출을 통해서 객체에 접근한다.
  • 이미지 출처: https://en.wikipedia.org/wiki/Singleton_pattern


구현

일반적인 구현

  • 침대를 만든다고 가정해보자.
  • 침대는 하나의 객체만 만들어져야한다고 생각하면 싱글턴 패턴으로 아래처럼 구현이 가능하다.

Bed

public class Bed {
    private static Bed bed = null;

    private Bed() {
    }

    public static Bed getBed() {
        if (bed == null) {
            bed = new Bed();
        }
        return bed;
    }

    public void print(String str) {
        System.out.println(str);
    }
}

User

public class User {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void print() {
        Bed.getBed().print(this.name + " " + "is in" + " " + Bed.getBed().toString() + " " + "bed");
    }
}

Main

public class Main {
    public static void main(String[] args) {
        final int NUM_OF_USERS = 6;
        User[] users = new User[NUM_OF_USERS];
        for (int i = 0; i < NUM_OF_USERS; ++i) {
            users[i] = new User(i + "-user");
            users[i].print();
        }
    }
}

Result

0-user is in com.company.Bed@60e53b93 bed
1-user is in com.company.Bed@60e53b93 bed
2-user is in com.company.Bed@60e53b93 bed
3-user is in com.company.Bed@60e53b93 bed
4-user is in com.company.Bed@60e53b93 bed
5-user is in com.company.Bed@60e53b93 bed
  • 위 클래스에서는 객체가 있는지 확인하고 있으면 반환하고 없다면 만들어서 반환해주는 구조
  • static를 사용해서 bed 변수와 getBed() 메소드를 만들었으며 이렇게 했기에 이 둘은 클래스 자체에 속하며 인스턴스 없이도 호출이 및 사용이 가능하다.
  • 이러한 방식을 통해 단 하나의 객체만 만들어서 사용할 수 있다.
  • 결과를 보면 모두 동일한 침대를 사용했다.


문제점

  • 만약 여러 스레드가 이 객체가 생성되기 전에 동시에 접근한다면 경합 조건(Race Condition)이 발생할 수 있다.
  • 객체를 만들기전에 스레드가 동시에 접근하면 객체를 여러개 만들게되는 상황에 직면할 수 있다.
  • 하단의 예제는 Thread.sleep(10)을 통해 객체를 여러개 생성하는 경우를 만들어본 결과이다.

Bed

public class Bed {
    private static Bed bed = null;

    private Bed() {
    }

    public static Bed getBed() {
        if (bed == null) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                System.out.println(e.toString());
            }
            bed = new Bed();
        }
        return bed;
    }

    public void print(String str) {
        System.out.println(str);
    }
}

User

public class User extends Thread {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void run() {
        Bed.getBed().print(this.name + " " + "is in" + " " + Bed.getBed().toString() + " " + "bed");
    }
}

Main

public class Main {
    public static void main(String[] args) {
        final int NUM_OF_USERS = 6;
        User[] users = new User[NUM_OF_USERS];
        for (int i = 0; i < NUM_OF_USERS; ++i) {
            users[i] = new User(i + "-user");
            users[i].start();
        }
    }
}

Result

0-user is in com.company.Bed@4d0c434e bed
2-user is in com.company.Bed@4d0c434e bed
5-user is in com.company.Bed@135b88ad bed
1-user is in com.company.Bed@17733f02 bed
3-user is in com.company.Bed@4d0c434e bed
4-user is in com.company.Bed@2c79921e bed
  • 이처럼 스레드가 동시에 접근하게 되면 하나의 객체만을 만들어서 사용하려는 싱글턴 패턴의 구현에 실패하게 된다.


문제 해결 구현법 - 정적 변수에 바로 초기화

  • 클래스에서 변수를 생성함과 동시에 객체를 만든다.
  • private static final Bed bed = new Bed();처럼 생성과 동시에 객체를 만들어준다.

Bed

public class Bed {
    private static final Bed bed = new Bed();

    private Bed() {
    }

    public static Bed getBed() {
        if (bed == null) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                System.out.println(e.toString());
            }
        }
        return bed;
    }

    public void print(String str) {
        System.out.println(str);
    }
}

User

public class User extends Thread {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void run() {
        Bed.getBed().print(this.name + " " + "is in" + " " + Bed.getBed().toString() + " " + "bed");
    }
}

Main

public class Main {
    public static void main(String[] args) {
        final int NUM_OF_USERS = 6;
        User[] users = new User[NUM_OF_USERS];
        for (int i = 0; i < NUM_OF_USERS; ++i) {
            users[i] = new User(i + "-user");
            users[i].start();
        }
    }
}

Result

1-user is in com.company.Bed@6fa76e7 bed
3-user is in com.company.Bed@6fa76e7 bed
2-user is in com.company.Bed@6fa76e7 bed
0-user is in com.company.Bed@6fa76e7 bed
4-user is in com.company.Bed@6fa76e7 bed
5-user is in com.company.Bed@6fa76e7 bed
  • 모두 똑같이 하나의 객체에 접근했음을 알 수 있다.


문제 해결 구현법 - 인스턴스 생성 메소드 동기화

  • synchronized를 이용해 여러 스레드가 동시에 메소드에 접근하는걸 방지한다.

Bed

public class Bed {
    private static Bed bed = null;

    private Bed() {
    }

    public synchronized static Bed getBed() {
        if (bed == null) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                System.out.println(e.toString());
            }
            bed = new Bed();
        }
        return bed;
    }

    public void print(String str) {
        System.out.println(str);
    }
}

User

public class User extends Thread {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void run() {
        Bed.getBed().print(this.name + " " + "is in" + " " + Bed.getBed().toString() + " " + "bed");
    }
}

Main

public class Main {
    public static void main(String[] args) {
        final int NUM_OF_USERS = 6;
        User[] users = new User[NUM_OF_USERS];
        for (int i = 0; i < NUM_OF_USERS; ++i) {
            users[i] = new User(i + "-user");
            users[i].start();
        }
    }
}

Result

5-user is in com.company.Bed@6fa76e7 bed
2-user is in com.company.Bed@6fa76e7 bed
0-user is in com.company.Bed@6fa76e7 bed
4-user is in com.company.Bed@6fa76e7 bed
3-user is in com.company.Bed@6fa76e7 bed
1-user is in com.company.Bed@6fa76e7 bed
  • 모두 똑같이 하나의 객체에 접근했음을 알 수 있다.


문제점

  • 스레드를 2가지 방식으로 해결했어도 아래처럼 클래스에서 상태를 유지해야하는 변수가 있다면 이야기가 달라진다.
  • cnt의 값이 일관적이지 않다.

Bed

public class Bed {
    private static Bed bed = null;
    private static int cnt = 0;

    private Bed() {
    }

    public synchronized static Bed getBed() {
        if (bed == null) {
            bed = new Bed();
        }
        return bed;
    }

    public void print(String str) {
        cnt++;
        System.out.println(str + " " + "cnt: " + cnt);
    }
}

User

public class User extends Thread {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void run() {
        Bed.getBed().print(this.name + " " + "is in" + " " + Bed.getBed().toString() + " " + "bed");
    }
}

Main

public class Main {
    public static void main(String[] args) {
        final int NUM_OF_USERS = 6;
        User[] users = new User[NUM_OF_USERS];
        for (int i = 0; i < NUM_OF_USERS; ++i) {
            users[i] = new User(i + "-user");
            users[i].start();
        }
    }
}

Result

1-user is in com.company.Bed@1f904935 bed cnt: 2
4-user is in com.company.Bed@1f904935 bed cnt: 2
0-user is in com.company.Bed@1f904935 bed cnt: 2
3-user is in com.company.Bed@1f904935 bed cnt: 3
2-user is in com.company.Bed@1f904935 bed cnt: 3
5-user is in com.company.Bed@1f904935 bed cnt: 4


문제 해결 구현법 - 메소드 안에 동기화 부분 추가

  • synchronized()를 이용해 스레드의 동시 접근을 막을 부분을 감싸주면 된다.
  • synchronized(this)는 해당 객체에 대한 동기화를 의미합니다.

Bed

public class Bed {
    private static Bed bed = null;
    private static int cnt = 0;

    private Bed() {
    }

    public synchronized static Bed getBed() {
        if (bed == null) {
            bed = new Bed();
        }
        return bed;
    }

    public void print(String str) {
        synchronized (this) {
            cnt++;
            System.out.println(str + " " + "cnt: " + cnt);
        }
    }

    /*
    public synchronized void print(String str) {
        cnt++;
        System.out.println(str + " " + "cnt: " + cnt);
    }
    */
}

User

public class User extends Thread {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void run() {
        Bed.getBed().print(this.name + " " + "is in" + " " + Bed.getBed().toString() + " " + "bed");
    }
}

Main

public class Main {
    public static void main(String[] args) {
        final int NUM_OF_USERS = 6;
        User[] users = new User[NUM_OF_USERS];
        for (int i = 0; i < NUM_OF_USERS; ++i) {
            users[i] = new User(i + "-user");
            users[i].start();
        }
    }
}

Result

0-user is in com.company.Bed@4f90c612 bed cnt: 1
3-user is in com.company.Bed@4f90c612 bed cnt: 2
2-user is in com.company.Bed@4f90c612 bed cnt: 3
1-user is in com.company.Bed@4f90c612 bed cnt: 4
4-user is in com.company.Bed@4f90c612 bed cnt: 5
5-user is in com.company.Bed@4f90c612 bed cnt: 6
  • 이제 cnt 값도 정상적으로 나오며 객체도 하나만 생성된다.


싱글턴 패턴과 정적 클래스의 비교


참고자료

Update(2020.07.18): Modify example and code.

Post about Singleton Pattern.


Environment and Prerequisite

  • Java


What is Singleton Pattern?

Singleton Pattern

  • Singleton Pattern: Software design pattern that restricts the instantiation of a class to one single instance. It access to its instance by using like getInstance() method or function.
  • Image Source: https://en.wikipedia.org/wiki/Singleton_pattern


Implementation

Usual Case Implementation

  • Let’s imagine we make bed.
  • Consider bed should be only one instance, so then we can use singleton pattern like below.

Bed

public class Bed {
    private static Bed bed = null;

    private Bed() {
    }

    public static Bed getBed() {
        if (bed == null) {
            bed = new Bed();
        }
        return bed;
    }

    public void print(String str) {
        System.out.println(str);
    }
}

User

public class User {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void print() {
        Bed.getBed().print(this.name + " " + "is in" + " " + Bed.getBed().toString() + " " + "bed");
    }
}

Main

public class Main {
    public static void main(String[] args) {
        final int NUM_OF_USERS = 6;
        User[] users = new User[NUM_OF_USERS];
        for (int i = 0; i < NUM_OF_USERS; ++i) {
            users[i] = new User(i + "-user");
            users[i].print();
        }
    }
}

Result

0-user is in com.company.Bed@60e53b93 bed
1-user is in com.company.Bed@60e53b93 bed
2-user is in com.company.Bed@60e53b93 bed
3-user is in com.company.Bed@60e53b93 bed
4-user is in com.company.Bed@60e53b93 bed
5-user is in com.company.Bed@60e53b93 bed
  • Above class makes instance if there is no instance. If instance exists, then return the instance.
  • Use static to make bed variable and getBed() method. bed variable and getBed() method are belong to class so it can be used without instance.
  • By using like this, we can make only one instance.
  • Result shows that there is only one bed instance.


Problem

  • There can be a race condition if multi threads access to this instance simultaneously before instantiation.
  • There can be multiple instances if threads access simultaneously before making instance.
  • Below example uses Thread.sleep(10) to make multiple instances.

Bed

public class Bed {
    private static Bed bed = null;

    private Bed() {
    }

    public static Bed getBed() {
        if (bed == null) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                System.out.println(e.toString());
            }
            bed = new Bed();
        }
        return bed;
    }

    public void print(String str) {
        System.out.println(str);
    }
}

User

public class User extends Thread {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void run() {
        Bed.getBed().print(this.name + " " + "is in" + " " + Bed.getBed().toString() + " " + "bed");
    }
}

Main

public class Main {
    public static void main(String[] args) {
        final int NUM_OF_USERS = 6;
        User[] users = new User[NUM_OF_USERS];
        for (int i = 0; i < NUM_OF_USERS; ++i) {
            users[i] = new User(i + "-user");
            users[i].start();
        }
    }
}

Result

0-user is in com.company.Bed@4d0c434e bed
2-user is in com.company.Bed@4d0c434e bed
5-user is in com.company.Bed@135b88ad bed
1-user is in com.company.Bed@17733f02 bed
3-user is in com.company.Bed@4d0c434e bed
4-user is in com.company.Bed@2c79921e bed
  • Like this, if threads access simultaneously then it fails to make one instance in singleton pattern.


Solution - Instantiate when initialize class

  • Make instance immediately when make variable in class.
  • Like private static final Bed bed = new Bed();, make instance immediately.

Bed

public class Bed {
    private static final Bed bed = new Bed();

    private Bed() {
    }

    public static Bed getBed() {
        if (bed == null) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                System.out.println(e.toString());
            }
        }
        return bed;
    }

    public void print(String str) {
        System.out.println(str);
    }
}

User

public class User extends Thread {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void run() {
        Bed.getBed().print(this.name + " " + "is in" + " " + Bed.getBed().toString() + " " + "bed");
    }
}

Main

public class Main {
    public static void main(String[] args) {
        final int NUM_OF_USERS = 6;
        User[] users = new User[NUM_OF_USERS];
        for (int i = 0; i < NUM_OF_USERS; ++i) {
            users[i] = new User(i + "-user");
            users[i].start();
        }
    }
}

Result

1-user is in com.company.Bed@6fa76e7 bed
3-user is in com.company.Bed@6fa76e7 bed
2-user is in com.company.Bed@6fa76e7 bed
0-user is in com.company.Bed@6fa76e7 bed
4-user is in com.company.Bed@6fa76e7 bed
5-user is in com.company.Bed@6fa76e7 bed
  • All threads access to only one instance.


Solution - Synchronize instance construction method

  • Use synchronized to prevent from accessing multiple threads to method simultaneously.

Bed

public class Bed {
    private static Bed bed = null;

    private Bed() {
    }

    public synchronized static Bed getBed() {
        if (bed == null) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                System.out.println(e.toString());
            }
            bed = new Bed();
        }
        return bed;
    }

    public void print(String str) {
        System.out.println(str);
    }
}

User

public class User extends Thread {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void run() {
        Bed.getBed().print(this.name + " " + "is in" + " " + Bed.getBed().toString() + " " + "bed");
    }
}

Main

public class Main {
    public static void main(String[] args) {
        final int NUM_OF_USERS = 6;
        User[] users = new User[NUM_OF_USERS];
        for (int i = 0; i < NUM_OF_USERS; ++i) {
            users[i] = new User(i + "-user");
            users[i].start();
        }
    }
}

Result

5-user is in com.company.Bed@6fa76e7 bed
2-user is in com.company.Bed@6fa76e7 bed
0-user is in com.company.Bed@6fa76e7 bed
4-user is in com.company.Bed@6fa76e7 bed
3-user is in com.company.Bed@6fa76e7 bed
1-user is in com.company.Bed@6fa76e7 bed
  • All threads access to only one instance.


Problem

  • Even though above multiple thread problems are solved, if there is variable in class like below then there comes another problem.
  • cnt’s value is not consistent.

Bed

public class Bed {
    private static Bed bed = null;
    private static int cnt = 0;

    private Bed() {
    }

    public synchronized static Bed getBed() {
        if (bed == null) {
            bed = new Bed();
        }
        return bed;
    }

    public void print(String str) {
        cnt++;
        System.out.println(str + " " + "cnt: " + cnt);
    }
}

User

public class User extends Thread {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void run() {
        Bed.getBed().print(this.name + " " + "is in" + " " + Bed.getBed().toString() + " " + "bed");
    }
}

Main

public class Main {
    public static void main(String[] args) {
        final int NUM_OF_USERS = 6;
        User[] users = new User[NUM_OF_USERS];
        for (int i = 0; i < NUM_OF_USERS; ++i) {
            users[i] = new User(i + "-user");
            users[i].start();
        }
    }
}

Result

1-user is in com.company.Bed@1f904935 bed cnt: 2
4-user is in com.company.Bed@1f904935 bed cnt: 2
0-user is in com.company.Bed@1f904935 bed cnt: 2
3-user is in com.company.Bed@1f904935 bed cnt: 3
2-user is in com.company.Bed@1f904935 bed cnt: 3
5-user is in com.company.Bed@1f904935 bed cnt: 4


Solution - Add synchronized in method

  • Cover method with synchronized() to prevent from simultaneous threads access.
  • synchronized(this) means sync to its instance.

Bed

public class Bed {
    private static Bed bed = null;
    private static int cnt = 0;

    private Bed() {
    }

    public synchronized static Bed getBed() {
        if (bed == null) {
            bed = new Bed();
        }
        return bed;
    }

    public void print(String str) {
        synchronized (this) {
            cnt++;
            System.out.println(str + " " + "cnt: " + cnt);
        }
    }

    /*
    public synchronized void print(String str) {
        cnt++;
        System.out.println(str + " " + "cnt: " + cnt);
    }
    */
}

User

public class User extends Thread {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void run() {
        Bed.getBed().print(this.name + " " + "is in" + " " + Bed.getBed().toString() + " " + "bed");
    }
}

Main

public class Main {
    public static void main(String[] args) {
        final int NUM_OF_USERS = 6;
        User[] users = new User[NUM_OF_USERS];
        for (int i = 0; i < NUM_OF_USERS; ++i) {
            users[i] = new User(i + "-user");
            users[i].start();
        }
    }
}

Result

0-user is in com.company.Bed@4f90c612 bed cnt: 1
3-user is in com.company.Bed@4f90c612 bed cnt: 2
2-user is in com.company.Bed@4f90c612 bed cnt: 3
1-user is in com.company.Bed@4f90c612 bed cnt: 4
4-user is in com.company.Bed@4f90c612 bed cnt: 5
5-user is in com.company.Bed@4f90c612 bed cnt: 6
  • Now cnt is printed well and there is only one instance.


Comparison between singleton pattern and static class


Reference