클래스 생성
class Api {
url: string;
ajax: XMLHttpRequest;
constructor(url:string){
this.url = url;
this.ajax = new XMLHttpRequest();
}
// protected를 사용하므로써 class 밖에서 인스턴스 객체로 등장하지 않게 한다.
protected getRequest<AjaxResponse>():AjaxResponse{
this.ajax.open('GET', this.url, false);
this.ajax.send();
return JSON.parse(this.ajax.response);
}
}
class NewsFeedApi extends Api {
getData() : INewsFeed[] {
return this.getRequest<INewsFeed[]>();
}
}
class NewsDetailApi extends Api {
getData() : INewsDetail {
return this.getRequest<INewsDetail>();
}
}
클래스 호출
// 인스턴스 생성시 매개변수 전달
const NewsFeeds = new NewsFeedApi(NEWS_URL)
newsFeed = store.feeds = makeFeeds(NewsFeeds.getData());
// 인스턴스 생성시 매개변수 전달
const NewsFeeds = new NewsDetailApi(CONTENT_URL.replace('@id', id))
const newsContent = NewsFeeds.getData()
기존의 단순 함수였던 코드를 클래스형 형태로 바꿀 때, 훨씬 더 코드가 무거워지는 경우가 있다.
특히나 작성한 코드가 하는 일이 작을때 이런 현상이 발생한다.
하지만 함수가 해야하는 일이 많아질수록, 함수 내에 작성해야 하는 코드가 많아질수록 점점 복잡도는 증가할 것이다.
함수는 구조가 없다. 단순히 입력된 statement를 읽고 실행할 뿐이다.
클래스는 구조라는 것을 갖게 된다. 즉 틀이라는 형식을 갖게 되는 것이다.
클래스는 만들어지는 목적이 있기 때문에 구조를 갖추는 것이며 나중에 기능이 추가될 때에도 초기의 복잡도는 유지되는 장점이 있다.
좋아진 것 같지 않고 나빠진 것 같다고 생각했을 때, 코드가 확장되었을 때를 생각하자.
class Api {
//constructor를 삭제했다.
// constructor(){ }
// 생성자가 없으니 getRequest가 직접 url을 받는다.
getRequest<AjaxResponse>(url: string): AjaxResponse {
// 인스턴스를 생성하지 않으니 this를 삭제한다.
const ajax = new XMLHttpRequest();
ajax.open('GET', url, false);
ajax.send();
return JSON.parse(ajax.response);
}
}
class Api {
getRequest<AjaxResponse>(url: string): AjaxResponse {
const ajax = new XMLHttpRequest();
ajax.open('GET', url, false);
ajax.send();
return JSON.parse(ajax.response);
}
}
// extends를 삭제한다.
class NewsFeedApi {
getData(): INewsFeed[] {
return this.getRequest<INewsFeed[]>();
}
}
// extends를 삭제한다
class NewsDetailApi {
getData(): INewsDetail {
return this.getRequest<INewsDetail>();
}
}
class NewsFeedApi {
getData(): INewsFeed[] {
return this.getRequest<INewsFeed[]>(NEWS_URL);
}
}
class NewsDetailApi {
//CONTENT_URL은 단독으로 사용될 수 없으니 id 값을 가져온다.
getData(id): INewsDetail {
return this.getRequest<INewsDetail>(CONTENT_URL.replace('@id', id));
}
}
function applyApiMixins(targetClass:any,bassClasses:any[]):void{
bassClasses.forEach(bassClass => {
Object.getOwnPropertyNames(bassClass.prototype).forEach(name => {
const descriptor = Object.getOwnPropertyDescriptor(bassClass.prototype, name);
if(descriptor){
Object.defineProperty(targetClass.prototype, name, descriptor);
}
});
});
}
//typescript는 class의 합성까지는 예측하지 못하기에
// interface를 통해 class가 합성될 것이라고 알려준다.
interface NewsFeedApi extends Api {};
interface NewsDetailApi extends Api {};
applyApiMixins(NewsFeedApi,[Api]);
applyApiMixins(NewsDetailApi,[Api]);