이전 피드에서 News라는 인터페이스를 기반으로 NewsFeed를 만들고, NewsDetail를 만들고, NewsComment를 만들었습니다.
이런 식으로 공통 요소를 만들고, 공통 요소를 확잘 할 수 있는 개별 요소를 만드는 것이 상속의 개념입니다.
코드를 작성할 때, 목적에 부합되도록 분류하고, 그 분류 내에서 훨씬 더 의미를 잘 부여할 수 있게, 중복된 코드를 제거한다면, 코드 가독성에 기여할 수 있습니다.
이를 위한 첫번째 방법이 클래스입니다.
// 네트워크를 통해서 API를 호출하는 함수 getData
function getData<AjaxResponse>(url: string): AjaxResponse {
ajax.open('GET', url, false);
ajax.send();
return JSON.parse(ajax.response);
}
// 뷰와 관련된 업데이트를 처리하는 함수 makeFeeds, 함수 updateView
function makeFeeds(feeds: NewsFeed[]): NewsFeed[] {
for (let i = 0; i < feeds.length; i++) {
feeds[i].read = false;
}
return feeds;
}
function updateView(html: string): void {
if (container) {
container.innerHTML = html;
} else {
console.error('최상위 컨테이너가 없어 UI를 진행하지 못합니다.');
}
}
// 메인 뷰를 처리하는 함수 NewsFeed, 함수 NewsDetail
function newsFeed(): void {
let newsFeed: NewsFeed[] = store.feeds;
const newsList = [];
let template = `
<div class="bg-gray-600 min-h-screen">
...
</div>
`
if (newsFeed.length === 0) {
newsFeed = store.feeds = makeFeeds(getData<NewsFeed[]>(NEWS_URL));
}
...
updateView(template);
}
function newsDetail(): void {
const id = location.hash.substring(7);
const newsContent = getData<NewsDetail>(CONTENT_URL.replace('@id', id))
let template = `...`
...
}
해당 피드에서는 공통요소로 작용하는 함수 getData에 집중하도록 하겠습니다.
API를 호출하는 함수 getData를 사용하는 입장인 함수 NewsFeed, 함수 NewsDetail에서 getData라는 명칭만으로는 정확히 어떤 타입의 데이터를 가져오는지 의미를 갖고 있지 않습니다.
function newsFeed(): void {
newsFeed = store.feeds = makeFeeds(getData<NewsFeed[]>(NEWS_URL));
}
function newsDetail(): void {
const id = location.hash.substring(7);
const newsContent = getData<NewsDetail>(CONTENT_URL.replace('@id', id))
}
즉, 공통함수를 사용하는 입장에서 좀 더 의미화 가 필요합니다.
class Api {
url: string;
ajax: XMLHttpRequest;
constructor(url: string) {
this.url = url;
this.ajax = new XMLHttpRequest();
}
}
class NewsFeedApi extends Api {
getData(): NewsFeed[] {
ajax.open('GET', url, false);
ajax.send();
return JSON.parse(ajax.response);
}
}
class NewsDetailApi extends Api {
getData(): NewsDetail {
ajax.open('GET', url, false);
ajax.send();
return JSON.parse(ajax.response);
}
}
class Api {
ajax: XMLHttpRequest;
url: string;
constructor(url: string) {
this.ajax = new XMLHttpRequest();
this.url = url;
}
getRequest<AjaxResponse>(): AjaxResponse {
this.ajax.open("GET", this.url, false);
this.ajax.send();
return JSON.parse(this.ajax.response);
}
}
class NewsFeedApi extends Api {
getData(): NewsFeed[] {
return this.getRequest<NewsFeed[]>();
}
}
class NewsDetailApi extends Api {
getData(): NewsDetail {
return this.getRequest<NewsDetail>();
}
}
function newsFeed(): void {
const api = new NewsFeedApi(NEWS_URL);
...
newsFeed = store.feeds = makeFeeds(api.getData<NewsFeed[]>(NEWS_URL));
}
function newsDetail(): void {
const id = location.hash.substring(7);
const newsContent = getData<NewsDetail>(CONTENT_URL.replace('@id', id))
}
바로, Protected입니다.
class Api {
ajax: XMLHttpRequest;
url: string;
constructor(url: string) {
this.ajax = new XMLHttpRequest();
this.url = url;
}
protected getRequest<AjaxResponse>(): AjaxResponse {
this.ajax.open("GET", this.url, false);
this.ajax.send();
return JSON.parse(this.ajax.response);
}
}