NimでFactoryパターンを実装する
概要
以前からfactory(又はstrategy)をNimで実装できないかということを、ちょこちょこ調べていた。
今回、実装に成功したので、そのことを以下に記載する。
環境
Nim Compiler Version 1.4.0 [Linux: amd64]
ソースコード
ソースコードの説明
以下にソースコードの説明を記載していく。
1行目~2行目
type AnimalKind {.pure.} = enum DOG, CAT, BIRD
あとでFactoryのcreate部分で使うAnimalKindという名前のenumを定義。
pragmaの一種である{.pure.}をつけることによって必ずAnimalKind.DOGといった形で呼び出さなければならなくなる。
(DOG単体で呼び出そうとするとエラーになる)
o AnimalKind.DOG x DOG
4行目~6行目
type Animal = ref object of RootObj name: string kind: AnimalKind
継承元のオブエジェクトを作成する。
プロパティは2つでありnameをstring型, kindをAnimalKind型で定義。
objectだとヒープ領域に作られずに動的にできないのでref objectにしている。
ref objectにしないとFactoryでcreate出来なくなるので注意。
恐らくコンパイルは通っても実行でエラーになるだろう。
8行目
method getKind(animal: Animal): string {.base.} = "ANIMAL"
先程定義したAnimalにBaseとなるmethodを定義する。
今回は分かりやすくgetKindと叩かれると何かしらの文字列が帰ってくるだけというシンプルなmethodにした。
nimには他にもprocやfuncといった関数の定義方法があるが オブジェクト思考で実装する場合は、methodを使う。
(procとfuncは手続き型で使ってfuncは副作用を許さない固い関数を定義出来る)
10行目~17行目
type Dog = ref object of Animal method getKind(dog: Dog): string = "DOG" type Cat = ref object of Animal method getKind(cat: Cat): string = "CAT" type Bird = ref object of Animal method getKind(bird: Bird): string = "BIRD"
ref object of XXXで継承する。
Animalを継承したDog、Cat、Birdクラスを定義し、それぞれ別の文字列が帰ってくるgetKindメソッドを定義する。
19行目~24行目
type AnimalFactory = object func create*(factory: AnimalFactory, kind: AnimalKind): Animal = case kind of AnimalKind.DOG: return Dog(name: "xxx", kind: kind) of AnimalKind.CAT: return Cat(name: "ooo", kind: kind) of AnimalKind.BIRD: return Bird(name: "iii", kind: kind)
今回の目的であるAnimalを作成するAnimalFactoryを実装。
ヒープ領域を使う必要がないのでobjectで定義。
アスタリスク(*)をつけることで外から、この関数を叩けるようになる。
戻り値の型をAnimalにすることにより、Animalを継承しているDog, Cat, Birdが返却できるようになる。
26行目~35行目
let factory = AnimalFactory() let dog = factory.create(AnimalKind.DOG) echo dog.getKind() let cat = factory.create(AnimalKind.CAT) echo cat.getKind() let bird = factory.create(AnimalKind.BIRD) echo bird.getKind()
AnimalFactoryを実際に使用する。
タグとしてAnimalKindをわたしてdog, cat, birdを作成している。
echoで異なる結果が出力されたのなら成功。
実行結果は以下となる。
DOG CAT BIRD