(1) и (2) действительно одинаковы, только синтаксически различны. Одна из проблем с (4) состоит в том, что если вы хотите работать с различными постоянными типами (плоские файлы, базы данных и т. Д.), Вам потребуется класс для каждой перестановки (AlsationToFileDAL, AlsationToSybaseDAL и т. Д.).
Вы можете использовать (1) / (2) с двойной отправкой, например ::100100
// pets.h
#include <string>
#include <iostream>
class Alsation;
class Persian;
class PetDAL
{
public:
virtual ~PetDAL () {}
virtual void save (const Alsation* alsation) = 0;
virtual void save (const Persian* persian) = 0;
};
class Pet
{
std::string name_;
public:
Pet (const std::string& name) : name_ (name)
{}
virtual ~Pet () {}
std::string getName () const
{
return name_;
}
virtual void save (PetDAL* dal) const = 0;
};
class Dog : public Pet
{
bool sleepWalks_;
public:
Dog (const std::string& name, bool sleepWalks) : Pet (name), sleepWalks_ (sleepWalks)
{}
bool getSleepWalks () const {return sleepWalks_;}
};
class Alsation : public Dog
{
public:
Alsation (const std::string& name, bool sleepWalks) : Dog (name, sleepWalks)
{}
virtual void save (PetDAL* dal) const
{
dal->save (this);
}
};
class Cat : public Pet
{
int purrsPerMinute_;
public:
Cat (const std::string& name, int purrsPerMinute) : Pet (name), purrsPerMinute_ (purrsPerMinute)
{}
int getPurrsPerMinute () const {return purrsPerMinute_;}
};
class Persian : public Cat
{
public:
Persian (const std::string& name, int purrsPerMinute) : Cat (name, purrsPerMinute)
{}
virtual void save (PetDAL* dal) const
{
dal->save (this);
}
};
class PetDALCoutImpl : public PetDAL
{
public:
virtual void save (const Alsation* alsation)
{
std::cout << "Saving alsation " << std::endl
<< "\tname=" << alsation->getName () << std::endl
<< "\tsleepwalks=" << alsation->getSleepWalks () << std::endl;
}
virtual void save (const Persian* persian)
{
std::cout << "Saving persian " << std::endl
<< "\tname=" << persian->getName () << std::endl
<< "\tpurrsPerMinute=" << persian->getPurrsPerMinute () << std::endl;
}
};
int test (int argc, char* argv[])
{
Dog* dog = new Alsation ("fido", true);
Cat* cat = new Persian ("dave", 10);
PetDAL* petDAL = new PetDALCoutImpl ();
dog->save (petDAL);
cat->save (petDAL);
delete cat;
delete dog;
return 0;
};
т.е. базовый класс Pet знает, что его подклассы могут быть сохранены в DAL, но он не зависит от реализаций DAL.