Encapsulate Collection, ์ปฌ๋ ‰์…˜ ์บก์Šํ™” ํ•˜๊ธฐ๋ฅผ ์•Œ์•„๋ณด์ž.

์š”์•ฝ

์ฝ”๋“œ

class Person {
    get courses() {return this._courses;}
    set courses(aList) {this._courses = aList;}
}
class Person {
    get courses() {return this._courses.slice();}
    addCourse(aCourse) {}
    removeCourse(aCourse) {}
}

๋ฐฐ๊ฒฝ

  • ์•ž์—์„œ ๊ฐ€๋ณ€ ๋ฐ์ดํ„ฐ๋Š” ์บก์Šํ™”ํ•˜๋Š”๊ฒŒ ์ข‹๋‹ค ํ–ˆ๋‹ค.
  • ๊ทธ๋Ÿฌ๋ฉด ์–ธ์ œ ์ˆ˜์ •๋˜๋Š”์ง€์— ๋Œ€ํ•œ ๊ฒƒ์„ ์–ด๋Š์ •๋„ ํ†ต์ œํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ทธ๋Ÿฐ๋ฐ ์‹ค์ˆ˜ํ•˜๊ธฐ ์ข‹์€ ๋ถ€๋ถ„์ด ์ปฌ๋ ‰์…˜์ด๋‹ค.
  • ๋ ˆ์ฝ”๋“œ์—์„œ ํŠน์ • ์ปฌ๋ ‰์…˜์„ ์ ‘๊ทผํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜์ž.
  • ์ผ๋‹จ ๊ฐ€์ ธ๊ฐ”๋Š”๋ฐ, ๊ทธ ๊ฐ€์ ธ๊ฐ„ ์ฝœ๋ ‰์…˜์˜ ์›์†Œ๋ฅผ ๋‹ค๋ฅธ ํ•จ์ˆ˜์—์„œ ๋ฐ”๊ฟจ๋‹ค.
  • ์ฐธ์กฐ๊ธฐ ๋•Œ๋ฌธ์— ์›๋ณธ ๋ฐ์ดํ„ฐ ์ž์ฒด๋„ ๋ณ€๊ฒฝ๋˜์–ด ๋ฒ„๋ฆฐ๋‹ค.
  • ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ์›๋ณธ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์ด ์ž์œ ๋กœ์›Œ ์–ด๋””์„œ ๋ณ€๊ฒฝ์ด ์ผ์–ด๋‚ฌ๋Š”์ง€ ์•Œ๊ธฐ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์— ๋””๋ฒ„๊น…์ด ์–ด๋ ค์›Œ์ง„๋‹ค.
  • ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๋ณต์ œ๋ณธ์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์„œ ๋ฌธ์ œ ๋ฐœ์ƒ ์ž์ฒด๋ฅผ ๋ง‰๋Š” ๊ฒƒ์ด๋‹ค.
    • ๋ณดํ†ต์€ ๋ณต์ œํ•œ๋‹ค๊ณ  ์„ฑ๋Šฅ์ €ํ•˜๊ฐ€ ํฌ์ง€ ์•Š๋‹ค.
  • ์•„๋‹ˆ๋ฉด ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ์ œ๊ณตํ•˜๊ฑฐ๋‚˜.
  • ๋ช…์‹ฌํ•ด์•ผ ํ•  ๊ฒƒ์€ ์ค‘๊ตฌ๋‚จ๋ฐฉ์œผ๋กœ ๋ฐฉ์‹์„ ๋‹ค๋ฅด๊ฒŒ ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด๋‹ค.
  • ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ์ผ๊ด€์„ฑ์„ ์ฃผ์–ด ์ปฌ๋ ‰์…˜ ํ•จ์ˆ˜ ๋™์ž‘ ๋ฐฉ์‹์„ ํ†ต์ผํ•ด์•ผ ํ•œ๋‹ค.

์ ˆ์ฐจ

  1. ์ปฌ๋ ‰์…˜์„ ์บก์Šํ™” ํ•œ๋‹ค.
  2. ์ปฌ๋ ‰์…˜์— ์›์†Œ๋ฅผ ์ถ”๊ฐ€/์ œ๊ฑฐํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
  3. ์ •์  ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  4. ์ปฌ๋ ‰์…˜์„ ์ฐธ์กฐํ•˜๋Š” ๋ถ€๋ถ„์„ ๋ชจ๋‘ ์ฐพ์•„์„œ, ์ปฌ๋ ‰์…˜์„ ์บก์Šํ™”ํ•œ ์ ‘๊ทผ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์ˆ˜์ •ํ•œ๋‹ค.
  5. ์ปฌ๋ ‰์…˜ ๊ฒŒํ„ฐ๋ฅผ ์ˆ˜์ •ํ•ด์„œ ์›๋ณธ ๋‚ด์šฉ์ด ์•„๋‹Œ ๋ณต์ œ๋ณธ์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•œ๋‹ค.
  6. ํ…Œ์ŠคํŠธํ•œ๋‹ค.

์˜ˆ์‹œ

class Person {
    constructor(name) {
        this._name = name;
        this._courses = [];
    }
    get name() {return this._name;}
    get courses() {return this._courses;}
    set courses(aList) {this._courses = aList;}
}
 
class Course {
    constructor(name, isAdvanced) {
        this._name = name;
        this._isAdvanced = isAdvanced;
    }
    get name() {return this._name;}
    get isAdvanced() {return this._isAdvanced;}
}
 
// Client 1
numAdvancedCourses = aPerson.courses.filter(c => c.isAdvanced).length;
 
// Client 2
const basicCourseNames = readBasicCourseNames(filename);
aPerson.courses = basicCourseNames.map(name => new Course(name, false));
 
// Client 3
for (const name of readBasicCourseNames(filename)) {
    aPerson.courses.push(new Course(name, false));
}
  • aPerson.courses๋Š” ์›๋ณธ ์ปฌ๋ ‰์…˜์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฑธ ๋ณ€๊ฒฝํ•˜๊ณ  ์žˆ๋Š” Client 2, 3์—์„œ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด ๋ฒ„๋ฆฐ๋‹ค.
  • ์›๋ณธ ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋– ํ•œ ๋ฐฉ์‹์œผ๋กœ๋“  ๋ฐ–์œผ๋กœ ๋ฑ‰๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ œ๋Œ€๋กœ๋œ ์บก์Šํ™”๊ฐ€ ๋˜์—ˆ๋‹ค๋ณด๊ธฐ ์–ด๋ ต๋‹ค.
class Person {
    constructor(name) {
        this._name = name;
        this._courses = [];
    }
 
    get courses() {
        return this._courses.slice();
    }
    set courses(aList) {
        this._courses = aList.slice();
    }
 
    addCourse(aCourse) {
        this._courses.push(aCourse);
    }
 
    removeCourse(aCourse, fnIfAbsent = () => {throw new RangeError();}) {
        const index = this._courses.indexOf(aCourse);
        if (index === -1) fnIfAbsent();
        else this._courses.splice(index, 1);
    }
}
 
// Client 3
for (const name of readBasicCourseNames(filename)) {
    aPerson.addCourse(new Course(name, false));
}
  • ์ผ๋‹จ add, remove๋ฅผ ๋ฉ”์„œ๋“œ๋กœ ์ œ๊ณตํ•˜์—ฌ ๋ณ€๊ฒฝํ•  ์‹œ ์ฒ˜๋ฆฌ ์ฝ”๋“œ๋ฅผ ๋‚ด๋ถ€๋กœ ๊ฒฉ๋ฆฌ์‹œ์ผฐ๋‹ค.
  • ๋˜ํ•œ set, get์„ ํ•  ์‹œ์—๋Š” ์›๋ณธ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š๊ณ , ๋ณต์ œ๋ณธ์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•˜์˜€๋‹ค.

Reference