私は小さなアドレス帳アプリケーションを書いていますが、データ ソース/バックエンドのインターフェイスに関して設計上のジレンマがあります。
データ ソース クラスの次の抽象基本クラスがあります。
class DataSource
{
private:
public:
virtual std::auto_ptr<Contact> getContact(int id) = 0;
virtual ContactRecordSet getAllContacts() = 0;
virtual bool addContact(const Contact& c) = 0;
virtual bool updateContact(int id, const Contact& c) = 0;
virtual bool deleteContact(int id)=0;
virtual ~DataSource() {};
};
以下は私のレコード構造体で、tmy レコード セットはこれらのオブジェクトの STL ベクトルに対する typedef です。
class Contact
{
public:
std::string firstName;
std::string lastName;
std::string phoneNumber;
std::string address;
std::string email;
};
typedef std::vector<Contact> ContactRecordSet;
私の質問は、DataSource::getContact() メソッドと DataSource::getAllContacts() メソッドに使用される戻り値の型と、クエリに基づいてレコードを取得する、まもなく追加される検索メソッドに関するものです。
一意の ID で検索しているため、DataSource::getContact() は 0 個または 1 個のレコードを返します。DataSource::getAllContacts() は 0 個以上の連絡先を返します。今後の検索方法では、0 個以上の連絡先が返されます。
私が今持っているように、 getContact() メソッドは auto_ptr を Contact に返しています。なぜなら、それらが複数になることは決してないことが確実にわかっている場合、ContactRecordSet を返すのは無駄に思え、レコードがない場合は NULL を返すことができるからです。そのIDを持っています。
インターフェイスの一貫性を保つために、 getContact() が ContactRecordSet も返す方がよいでしょうか?
私の一部は、単一のオブジェクトに対してそのようなデータ構造を返すという考えに苛立ちますが、一方で、より一貫性があり、そのIDの値が見つかったかどうかをチェックするためのセマンティクスは、全体的な抽象化とより一致しているように見えます設計 (返されたレコードセットの長さをチェックするか、NULL の auto_ptr をチェックします)。
皆さんはどう思いますか?
(注 - 私はおそらく単純なアドレス帳アプリケーションのために過度に設計していることを認識していますが、異なるバックエンド (フラットファイル、SQL など...) を簡単に交換できるようにしたいと考えています。目標は、優れたモジュール設計と関心の分離を実践することです。)
アップデート
反対の観点から見て、複数のレコード メソッドが auto_ptrs を ContactRecordSet objectcs に返すようにすることができると思います。そうすれば、a)常にオブジェクトへのポインターを取得するという点で一貫性があり、b)レコード セットが空の場合に std::vector を返すオーバーヘッドがなく、NULL ポインターを返すだけです。