クローラーの開発をしていて、Site1Crawler,Site2Crawlerといった形で数字の違うクローラーを作成、class名から動的に別々のクローラーのインスタンスを生成したかったのでその方法です。
ディレクトリは適当でいいのですが、今回4つのファイルを作成します。
- Crawler.ts
- 量産されたclassをまとめて書いておくファイル
- BaseCrawler.ts
- 継承される元となるclass。インターフェースとして書いてもいいが今回はclassで作成する
- Site1Crawler.ts(Site2Crawler.tsなどこのファイルを量産していく)
- BaseCrawlerを継承した動的に呼び出されるclass
- CrawlerFactory.ts
- 動的に呼び出す部分を記載するFactory class
まず最初に継承元となるBaseCrawlerのclassを作成します。
BaseCrawler.ts
export default class BaseCrawler
{
public siteId: number = 0;
constructor() {
this.init();
}
public init()
{
}
public crawling()
{
console.log(url);
}
}
次に量産するSite1Crawlerのclassを作成します。
Site1Crawler.ts
import BaseCrawler from "./BaseCrawler";
export default class Site1Crawler extends BaseCrawler
{
init(): void {
super.init();
this.siteId = 1;
}
crawling(): void {
super.crawling();
console.log("site1 crawler crawling");
}
}
量産されたclassをまとめて記載しておくファイルを作成します。
Crawler.ts
import Site1Crawler from "./Site1Crawler";
const Crawler: any = {
Site1Crawler,
(...量産していったらここにどんどん追加していく)
}
export default Crawler;
Factoryクラスの作成
CrawlerFactory.ts
import Crawler from "./Crawler";
import BaseCrawler from "./BaseCrawler";
export default class CrawlerFactory extends BaseCrawler{
constructor(className: string)
{
super();
if (Crawler[className] === undefined || Crawler[className] === null) {
throw new Error(`Class type of \'${className}\' is not in the store`);
}
return new Crawler[className]();
}
}
これで完了です。
呼び出す際には、
index.ts
import CrawlerFactory from "./CrawlerFactory";
import BaseCrawler from "./BaseCrawler";
const main = () {
//class名の文字列で呼び出す
const className = 'Site1Crawler';
const crawler: BaseCrawler = new CrawlerFactory(className);
crawler.crawling();
//loopさせて動的に呼び出して実行させる
//クローラーを10個作って順番に実行させたい場合
for (let i = 0; i < 10; i++) {
const className = `Site${i}Crawler`;
const crawler: BaseCrawler = new CrawlerFactory(className);
crawler.crawling();
}
}
のように記載可能です。
evalとかの方法もあると思いますが、この方法が一番しっくりきたので。
参考