
저번 Genesis block 만들기 편에서 작성한 코드를 대부분 갈아 엎고 Singleton Pattern으로 다시 짰다. Singleton Pattern 은 객체의 인스턴스가 오직 1개만 생성되는 패턴을 말한다. 이미 생성된 인스턴스를 활용하기 때문에 메모리와 속도면에서 장점을 가지며, 인스턴스가 1개만 존재한다는 것을 보증할 수 있다. 하지만 단점도 명확하다. 자세한 한계점은 이 글을 참조하고 코드부터 살펴보자.
package blockchain
type block struct {
data string
hash string
prevHash string
}
type blockchain struct {
blocks []block
}
var b *blockchain //변수 선언
func Getblockchain() *blockchain {
if b = nil { //변수가 선언만 된 상태에서
b = &blockchain{} // 최초로 initialize 해주겠다.
}
return b
}
먼저 main.go에 있던 struct를 외부(blockchain.go)로 빼줬다. 그 다음 blockchain struct의 인스턴스를 선언만 한 상태에서 Getblockchain() 함수를 통해 initialize 해준다. 이렇게 하면 외부에서 Getblockchain() 함수에만 접근할 수 있으며 initialize 하는 부분을 따로 조절해줄 수 있다.
nil을 통해서 변수가 선언만 된 상태인지 확인할 수 있는데, 첫 번째처럼 선언과 초기화를 모두 한 상태에서 nil 과 비교하면 false 가 나온다.
c := []int{} // 선언과 초기화
fmt.Println(c == nil) //false
var b *blockchain // 선언만
fmt.Println(b == nil) //true
//해시값 계산
func (b *block) calculateHash() {
hash := sha256.Sum256([]byte(b.data + b.prevHash))
b.hash = fmt.Sprintf("%x", hash)
}
//마지막 해시값 가져오기
func getLastHash() string {
totalBlocks := len(Getblockchain().blocks)
if totalBlocks == 0 {
return ""
}
return Getblockchain().blocks[totalBlocks-1].hash
}
//새 블록 생성
func createBlock(data string) *block {
newBlock := block{data, "", getLastHash()}
newBlock.calculateHash()
return &newBlock
}
//블록 추가
func (b *blockchain) Addblock(data string) {
b.blocks = append(b.blocks, createBlock(data))
}
기존 main.go에서 작성했던 함수들을 blockchain.go 파일로 옮기고, 각자 하나의 기능만 하도록 바꿨다. (calculateHash 함수 추가)