대체 가능성, 내적일관성 모두 객체 지향 언어의 필요 충분 조건
객체 지향 언어는 대체 가능성과 내적일관성을 유지한다 !
대체 가능성과 내적일관성을 지원 하는 언어는 객체 지향 언어이다 !
=> 대부분 통제불가 요소 !
이 간단한 주제가 아키텍쳐 이하 모든 디자인 패턴의 원형적인 목표라 할 수 있다.
if case =1 => case1함수
else if case =2 => case2함수, 공통함수
else if case =3 => case3함수, 공통함수
문제1) 공통함수, 공통data 사용
data share 문제 발생
공통함수에 의해 로직 수정시 전체 케이스를 살펴야함
문제2) case가 변경될때
case 추가시 or 삭제시 or 변경시에도 전체 코드를 살펴야함
해결) 객체 지향
함수가 가리키는 data를 은닉하고 캡슐화
함수의 data 직접 사용 및 직접 coupling 불가능하게 만들어야 함
상속위임 : 내부 계약관계로 추상층에서 공통 요소를 해결하고 상태를 공유할 수 있음 (객체 지향)
소유위임 : 외부 계약관계로 각각이 독립적인 문제를 해결하며 메세지를 주고 받는 것으로 문제를 해결함 (절차 지향)
상대적임을 알자!
코드 실행 시점에 먼저 필요한 것들은 static time에서 실행
코드 실행 이후 다시 위의 코드가 static timer라할 수 있음
실행시점에 필요한 변하지 않는 부분을 생각하며 static 으로 구현한다.
static으로 부터 위임 받아서 실행시점에서 실제 동작을 구현한다.
Template Pattern by 객체 지향형 내적 일관성의 원리
case 만큼의 객체가 만들어져야 하므로 메모리 비용 발생이 높다
1. Strategy Pattern by 함수형!
abc언어 : 식 vs 문
식 : 메모리에 직접 관련된 값, 메모리에 적재되는 값(or not), 값=식, 식=연산, 연산하는 함수 = 값
연산은 값과 교환, 값 = 연산 = 함수는 메모리 직접 관련되어 등가성을 지닌다해도 무방
메모리가 충분하면 연산을 줄이고 값으로 만들어 메모리 적재후 참조
메모리가 부족하면 연산으로 처리함.
컴퓨터 세계에서 분리되지 않는다.
값, 연산, 함수는 식이라는 등가성을 지닌다.
문 : compiler, interpereter가 프로그램을 돌릴때 참조하는 hint, 메모리에 사라짐
2. command pattern (문을 기억해두는 행위)
연산을 값으로 바꾸는 것
host
의 변화율은 관리를 할 수 없으므로, case를 모아둔 테이블로 관리하겠다는 차선책이라 볼 수 있다. hash table
에 add만 해주면 되도록 설계 "상태에 대한 분기는 사라지지 않는다"
문
을 제거해서 값
으로 바꿀수 있는 객체화 작업실행시점으로 분기를 옮길 떄의 장단점
장점
1. 정의 시점에 모든 경우를 몰라도 됨
2. 정의 시점에 그 경우를 처리하는 방법도 몰라도 됨
일정한 통제 범위 내에서 확장가능한 알고리즘설계 가능
단점
1. 실행 시점에 모든 경우를 반드시 기술해야 함
2. 실행 시점마다 알고리즘의 안정성을 담보해야 함
매 호스트코드마다 안정성을 따로 담보해야 함.
(모든 케이스가 값으로 정의되지 않으면 Run time error, context error 발생, frame전체가 약해짐)
확장성이 떨어지고 안정성이 중요하다면 기피해야함
Runtime 불안정성은 Static-time 불안정성에 연결된다
Trade off 고려 사항
캡슐화 패턴 : Factory, Builder pattern
격리
// Github.js
// 상속 위임
const Github = class{ // 정의 시점 - 변하지 않는 부분
constructor(id, repo){
this._base = `https://api.github.com/repos/${id}/${repo}/contents/`;
}
// 공통 부분 (template method)
load(path){
const id = 'callback' + Github._id++;
const f = Github[id] = ({data :{content}})=>{
delete Github[id];
document.head.removeChild(s);
this._loaded(content) //위임 부분
};
const s = document.createElement('script');
s.src = `${this._base + path}?callback=Github.${id}`;
document.head.appendChild(s);
}
_loaded(v){ throw 'override!' ;} // Hook (내부 hook을 통한 template pattern)
}
Github._id = 0;
// ImageLoader.js
const ImageLoader = class extends Github{ // 실행시점 = 변하는 부분
constructor(id, repo, target){
super(id, repo);
this._target = target;
}
// 위임 구현
_loaded(v){
this._target.src = 'data:text/plain;base64, ' + v;
}
}
// index.js
// 실행 context
const s75img = new ImageLoader(
'minchjung',
'imgloader',
document.querySelector('#a')
);
s75img.load('035d19cfbebc3b8479939736a5f7bfe4.jpg');
//Github.js
// 소유 위임
const Github = class{ // 정의 시점 - 변하지 않는 부분
constructor(id, repo){
this._base = `https://api.github.com/repos/${id}/${repo}/contents/`;
}
load(path){
if(!this._parser) return // parser 존재x kill
const id = 'callback' + Github._id++;
const f = Github[id] = ({data :{content}})=>{
delete Github[id];
document.head.removeChild(s);
console.log(this._parser)
this._parser[0](content, this._parser[1][0]) //위임 부분, 실행 부분 (invoker)
// this._parser[1] = ele 여야 하지만, [ ele , src] <-로 불러와짐
};
const s = document.createElement('script');
s.src = `${this._base + path}?callback=Github.${id}`;
document.head.appendChild(s);
}
setParser(f, ...arg){this._parser = [f, arg];} // 위임 객체 ( command pattern, command 객체 생성 )
// 실행시점 = 변하는 부분
}
Github._id = 0;
// index.js
const el = (name) => document.querySelector(name);
const img =(v,el)=>el.src = 'data:text/plain;base64, ' + v;
const loader = new Github('minchjung', 'imgloader');
loader.setParser(img, el('#a'));
loader.load('035d19cfbebc3b8479939736a5f7bfe4.jpg')
// Github.js
// 소유 위임 - with router
const Github = class{ // 정의 시점 - 변하지 않는 부분
constructor(id, repo){
this._base = `https://api.github.com/repos/${id}/${repo}/contents/`;
}
load(path){
if(!this._parser) return // parser 존재x kill
const id = 'callback' + Github._id++;
const f = Github[id] = ({data :{content}})=>{
delete Github[id];
document.head.removeChild(s);
console.log(this._parser)
this._parser[0](content, this._parser[1][0]) //위임 부분, 실행 부분 (invoker)
// this._parser[1] = ele 여야 하지만, [ ele , src] <-로 불러와짐
};
const s = document.createElement('script');
s.src = `${this._base + path}?callback=Github.${id}`;
document.head.appendChild(s);
}
setParser(f, ...arg){this._parser = [f, arg];} // 위임 객체 ( command pattern, command 객체 생성 )
// 실행시점 = 변하는 부분
}
Github._id = 0;
// Loader.js
// loader 이자 router 실행 시점에서 선택위임
const Loader = class{
constructor(id, repo){
this._git = new Github(id, repo);
this._router = new Map;
}
add(ext, f, ...arg){
ext.split(',').forEach(v=> this._router.set(v,[f, arg]));
}
load(v){
const ext = this._v.split('.').pop();
if(!this._router.has(ext)) return ;
this._git.setParser(...this._router.get(ext));
this._git.load(v);
}
}
// index.js
const el = (name) => document.querySelector(name);
const img =(v,el)=>el.src = 'data:text/plain;base64, ' + v;
const loader = new Github('minchjung', 'imgloader');
loader.setParser(img, el('#a'));
loader.load('035d19cfbebc3b8479939736a5f7bfe4.jpg')