イテレータパターン(リンクリスト版)
前回まで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); }