イテレータパターン(リンクリスト版)

前回までBookShelfはBook*の配列として実装していた。これをリンクリストを使用したもので実装し直してみる。なお配列版と比較してmain側が変更してあるのは汎用性を高めるためである。実際に使用しているコードであるのならば、使用しているコードを優先すべきであるが、学習用のコードであるために書き直しておいた。

Aggregate.h

#ifndef AGGREGATE_HEADER_FILE_INCLUDED__
#define AGGREGATE_HEADER_FILE_INCLUDED__

#include "Iterator.h"

/*!
	@brief	イテレータのコンストラクタ
	@param	p:コンクリートアグリゲータのインスタンスを指すポインタ
	@retval	生成したイテレータのインスタンスを指すポインタ
	@attention	実際の処理はコンクリートクラスにて実装のこと
	@attention	戻り値のインスタンスはIteratorDisposeで破棄すること
 */
Iterator *IteratorCreate(void *p);

/*!
	@brief	イテレータデストラクタ
	@param	IteratorCreateで生成したイテレータインスタンスを指すポインタ
	@retval	なし
	@attention	実際の処理はコンクリートクラスにて実装のこと
 */
void IteratorDispose(Iterator *p);

#endif	/* End of AGGREGATE_HEADER_FILE_INCLUDED__ */

Iterator.h

#ifndef ITERATOR_HEADER_FILE_INCLUDED__
#define ITERATOR_HEADER_FILE_INCLUDED__

/*! Iterator構造体 */
typedef struct Iterator_tag Iterator;

/*!
	@brief	次の要素があるかどうかの判定
	@param	p:イテレータインスタンスを指すポインタ
	@retval	0: 次の要素無し
	@retval	!0: 次の要素あり	
	@attention	!0の場合、IteratorNextが正常に実行できる
	@attention	実際の処理はコンクリートクラスにて実装のこと
 */
int IteratorHasNext(Iterator *p);

/*!
	@brief	要素を取得し、次の要素を指すようにする
	@param	p:イテレータインスタンスを指すポインタ
	@retval	取得した要素を指すポインタ	
	@attention	戻り値の型はvoid *なので適切なポインタで受けること
	@attention	実際の処理はコンクリートクラスにて実装のこと
 */
void *const IteratorNext(Iterator *p);

#endif	/* End of ITERATOR_HEADER_FILE_INCLUDED__ */

Book.h

#ifndef BOOK_HEADER_FILE_INCLUDED__
#define BOOK_HEADER_FILE_INCLUDED__

/*! Book構造体 */
typedef struct Book_tag Book;

/*!
	@brief	Bookコンストラクタ
	@param	pName: 書籍名
	@retval	生成されたBookオブジェクトを指すポインタ
	@attention	生成したオブジェクトはBookDisposeで破棄すること
 */
Book *BookCreate(const char *pName);

/*!
	@brief	Bookデストラクタ
	@param	pBook: Bookオブジェクトを指すポインタ
	@retval	無し
	@attention
 */
void BookDispose(Book *pBook);

/*!
	@brief	書籍名を返す
	@param	pBook: Bookオブジェクトを指すポインタ
	@retval	書籍名
	@attention	戻り値で得たポインタが指す領域を書き換えないこと
 */
char*const BookGetName(Book *pBook);

#endif

Book.c

#include "Book.h"
#include <string.h>
#include <stdlib.h>

/*! Book構造体 */
struct Book_tag {
	char *name;	/*!< 書籍名  */
};

Book *BookCreate(const char *pName)
{
	Book *pBook = NULL;

	pBook = malloc(sizeof(Book));
	if (pBook == NULL) {
		BookDispose(pBook);
		return NULL;
	}

	pBook->name = NULL;
	
	if (pName == NULL) {
		/* 書籍名が渡されない場合 */
		pBook->name = malloc(1);
		if (pBook->name) {
			BookDispose(pBook);
			return NULL;
		}
		/* 空文字列を設定する */
		pBook->name[0] = '\0';
	} else {
		pBook->name = malloc(strlen(pName) + 1);
		if (pBook->name == NULL) {
			BookDispose(pBook);
			return NULL;
		}
		strcpy(pBook->name, pName);
	}

	return pBook;
}

void BookDispose(Book *pBook)
{
	if (pBook != NULL) {
		free(pBook->name);
	}
	free(pBook);
}

char*const BookGetName(Book *pBook)
{
	char *const retName = (pBook)? pBook->name: NULL;

	return retName;
}

BookShelf.h

#ifndef BOOK_SHELF_HEADER_FILE_INCLUDED__
#define BOOK_SHELF_HEADER_FILE_INCLUDED__

#include "Book.h"
#include "Aggregate.h"

/*!
	@brief	コンクリートアグリゲータクラス
 */
typedef struct BookShelf_tag BookShelf;

/*!
	@brief	コンストラクタ
	@retval	生成したBookShelfのインスタンスを指すポインタ。生成に失敗した場合NULLが返る。
	@attention	戻り値のインスタンスはBookShelfDisposeで破棄すること
 */
BookShelf *BookShelfCreate(void);

/*!
	@brief	デストラクタ
	@param	p: BookShelfインスタンスを指すポインタ
	@attention	BookShelfに格納された本もまとめて破棄される
 */
void BookShelfDispose(BookShelf *p);

/*!
	@brief	pが指す本のインスタンスを指すポインタを返す
	@param	p: BookShelfインスタンスを指すポインタ
	@retval	本のインスタンスを指すポインタ
	@attention	取得したポインタをfreeしないこと。ダングリングポインタとなってしまう。
 */
Book *const BookShelfGetBookAt(BookShelf *p);

/*!
	@brief	本棚に本を加える
	@param	p: BookShelfインスタンスを指すポインタ
	@param	pBook: 本のインスタンスを指すポインタ
	@retval	成功0, 失敗-1
	@attention	本棚から本を取り除く関数は無い。BookShelfデストラクタで破棄すること
 */
int BookShelfAppendBook(BookShelf *p, char *const pName);

/*!
	@brief	次の要素を取得する
	@param	p: BookShelfインスタンスを指すポインタ
	@retval	pの次の要素
	@attention	取得したポインタをfreeしないこと。ダングリングポインタとなってしまう。
 */
BookShelf *const BookShelfGetNext(BookShelf *p);

#endif

BookShelf.c

#include "BookShelf.h"
#include "BookShelfIterator.h"
#include <stdlib.h>

/*!
	@brief	BookShelf構造体は単方向リンクリストである。
	@brief	先頭ノードはダミーノードであり、その次の要素から有効なノードである。
	@brief	最後尾ノードのpNextはNULLを指す
 */
struct BookShelf_tag{
	Book *pBook;		/*!< Bookインスタンスを指すポインタ */
	BookShelf *pNext;	/*!< 次の要素を指すポインタ  */
};

BookShelf *BookShelfCreate(void)
{
	BookShelf *p = NULL;

	p = malloc(sizeof(BookShelf));
	if (p == NULL) {
		return NULL;
	}

	/* 生成したときのインスタンスはダミーノードであり、NULLを設定する */
	p->pBook = NULL;
	p->pNext = NULL;
	
	return p;
}

void BookShelfDispose(BookShelf *p)
{
	BookShelf *pTmp;
	BookShelf *pDelNode;

	/* リストをたぐって全ノードを解放する */
	pTmp = p->pNext;
	while (pTmp != NULL) {
		pDelNode = pTmp;
		pTmp = pTmp->pNext;
		free(pDelNode);
	}
}

/*!
	@brief	メンバ変数pBookのGetter
	@param	p: BookShelfインスタンスを指すポインタ
	@retval	メンバ変数pBookの値
	@attention	取得したポインタをfreeしないこと。ダングリングポインタとなってしまう。
 */
Book *const BookShelfGetBookAt(BookShelf *p)
{
	return p->pBook;
}

/*!
	@brief	メンバ変数pNextのGetter
	@param	p: BookShelfインスタンスを指すポインタ
	@retval	メンバ変数pNextの値
	@attention	取得したポインタをfreeしないこと。ダングリングポインタとなってしまう。
 */

BookShelf *const BookShelfGetNext(BookShelf *p)
{
	return p->pNext;
}

int BookShelfAppendBook(BookShelf *p, char *const pName)
{
	BookShelf *pNewNode;
	Book *pBook;

	pNewNode = malloc(sizeof(BookShelf));
	if (pNewNode == NULL) {
		return -1;
	}

	pBook = BookCreate(pName);
	if (pBook == NULL) {
		return -2;
	}
	
	pNewNode->pBook = pBook;
	pNewNode->pNext = p->pNext;
	p->pNext = pNewNode;

	return 0;
}

/*!
	@brief	コンクリートイテレータのコンストラクタ
	@param	p:BokkShelfのインスタンスを指すポインタ
	@retval	生成したBookShelfItereatorインスタンスを指すポインタ
 */
Iterator *IteratorCreate(void *p)
{
	return BookShelfIteratorCreate(p);
}

/*!
	@brief	BookShelfIteratorデストラクタ
	@param	BookShelfIteratorCreateで生成したインスタンスを指すポインタ
	@retval	なし
 */
void IteratorDispose(Iterator *p)
{
	BookShelfIteratorDispose(p);
}

BookShelfIterator.h

#ifndef BOOK_SHELF_ITERATOR_HEADER_FILE_INCLUDED__
#define BOOK_SHELF_ITERATOR_HEADER_FILE_INCLUDED__

#include "Iterator.h"
#include "BookShelf.h"

/*!
	@brief	BookShelfIteratorコンストラクタ
	@param	p:BookShelfのインスタンスを指すポインタ
	@retval	生成したIteratorのインスタンスを指すポインタ
	@attention	戻り値のインスタンスはBookShelfDisposeで破棄すること
 */
Iterator *BookShelfIteratorCreate(BookShelf *p);

/*!
	@brief	BookShelfIteratorのデストラクタ
	@param	p: BookShelfIteratorインスタンスを指すポインタ
 */
void BookShelfIteratorDispose(Iterator *p);

#endif

BookShelfIterator.c

#include "BookShelfIterator.h"
#include "BookShelf.h"
#include "Book.h"
#include <stdlib.h>

struct Iterator_tag{
	BookShelf *pBookShelf;
};

int IteratorHasNext(Iterator *p)
{
	return (p->pBookShelf) ? 1: 0;
}

void *const IteratorNext(Iterator *p)
{
	Book *retVal;

	retVal = BookShelfGetBookAt(p->pBookShelf);
	p->pBookShelf = BookShelfGetNext(p->pBookShelf);
	
	return retVal;
}

Iterator *BookShelfIteratorCreate(BookShelf *pBookShelf)
{
	Iterator *pIte = NULL;

	pIte = malloc(sizeof(Iterator));
	if (pIte == NULL) {
		return NULL;
	}

	pIte->pBookShelf = BookShelfGetNext(pBookShelf);

	return pIte;
}

void BookShelfIteratorDispose(Iterator *p)
{
	free(p);
}