将对象转换为其他类

Converting object to a different class

本文关键字:其他 转换 对象      更新时间:2023-10-16

Sandy是Person类,他皈依了穆斯林并取了一个新名字Fatima,并具有Sandy的所有属性,具有新的穆斯林属性(例如宗教==伊斯兰教等(。在这一点上,桑迪可以被删除,现在的穆斯林阶层的法蒂玛将从此扮演桑迪的角色。问题是,由于她的新地址,所有认识桑迪的人都不认识法蒂玛。为所有认识桑迪的人手动将桑迪的地址更改为法蒂玛的地址显然不是一种可接受的方法。关于如何改进设计的任何建议?这是我显示问题的简化代码:

#include <iostream>
#include <string>
#include <typeinfo>
class Person {
        std::string name;
        Person* bestFriend;
    public:
        Person (const std::string& newName) : name (newName) {}
        virtual ~Person() = default;
        std::string getName() const {return name;}
        void setName (const std::string& newName) {name = newName;}
        Person* getBestFriend() const {return bestFriend;}
        void setBestFriend (Person* newBestFriend) {bestFriend = newBestFriend;}
};
class Muslim: public Person {
    public:
        Muslim (const Person& person) : Person (person) {
                          // religion = Islam; etc... 
                }
};
int main() {
    Person *mary = new Person ("Mary"), *sandy = new Person ("Sandy");
    mary->setBestFriend (sandy);
    std::cout << "sandy = " << sandy << ", " << typeid(*sandy).name() << std::endl;
    std::cout << mary->getName() << "'s best friend is " << mary->getBestFriend()->
    getName() << "." << std::endl;
    Muslim* fatima = new Muslim (static_cast<Muslim>(*sandy));  // the big change
    fatima->setName ("Fatima");  // should now delete sandy, because fatima takes on every attribue of sandy
    std::cout << "fatima = " << fatima << ", " << typeid(*fatima).name() << std::endl;
    std::cout << mary->getName() << "'s best friend is " << mary->getBestFriend()->
    getName() << "." << std::endl;  // still Sandy, of course
}

输出:

桑迪 = 0x32658,6 人

玛丽最好的朋友是桑迪。

法蒂玛=0x23fec0,6穆斯林

玛丽最好的朋友是桑迪。

当然,我们希望拥有:玛丽最好的朋友是法蒂玛,玛丽->getBestFriend((->getReligion(( == 伊斯兰教等......如何重新设计整个事情,以便自动化(假设有成千上万的人认识她(?

我想使用继承,因为类 Muslim 将有许多复杂的 Person 方法覆盖(以及许多新的数据成员和方法(。

正如@Joseph曼斯菲尔德在评论中建议的那样,我的第一个方法是将religion作为Person的属性。因此,更改仅意味着属性的更改,而不是新对象。

但是,如果必须使用

不同的类,则可以使用观察者模式。也就是说,任何朋友的人都应该订阅(在朋友通讯录中(列表以更改该人。此订阅服务器必须实现来自同一接口(订阅服务器(的方法,当Person对象的属性更改时,该方法应由 对象调用。

总结一下:

  • Person(friends(上列出每个朋友的地址列表。
  • 每个友元对象类都应该实现一个公共接口,其中声明了更改通知方法(friendChanged(...) (
  • Person通过创建新类的新对象进行更改时,它必须遍历其friends列表,调用friendChanged并向他们传递新的 person 对象地址。之后,您可以销毁和释放旧对象。

最后,我认为宗教不应该被代表为一个子类。在我看来,宗教是一个人的特征,因此,它应该是一个属性。有一个OOP原则说:赞成组合而不是继承。你的设计似乎人为地违背了这一原则。

class Person;
class ObserverPersonInterface {
    public:
        virtual void registerObserver (Person*) = 0;
        virtual void removeObserver (Person*) = 0;
        virtual void notifyObservers() const = 0;       
};
class AddressChangeData : public ObserverPersonInterface {
    public:
        void addressChange (const Person* oldPerson, Person* newPerson) {
            oldAddress = oldPerson;
            newAddress = newPerson;
            // observers.remove (oldAddress);  // but not relevant here
            notifyObservers();
        }
        virtual void registerObserver(Person* person) override {
            observers.emplace_back (person);
        }
        virtual void removeObserver(Person* person) override {
            observers.remove (person);
        }
    private:
        virtual inline void notifyObservers() const override;
        std::list<Person*> observers;  // should perhaps be a red-black tree for greater efficiency
        const Person *oldAddress;
        Person *newAddress;
} changeOfAddressData;
class Person {
    public:
        Person() {
            changeOfAddressData.registerObserver(this);
        }
        // every new Person constructed is registered to changeOfAddressData
        Person(const std::string& newName) : name (newName) {
            changeOfAddressData.registerObserver (this);
        }
        virtual ~Person() = default;
        std::string getName() const {return name;}
        void setName (const std::string& newName) {name = newName;}
        Person* getBestFriend() const {return bestFriend;}
        void setBestFriend (Person* newBestFriend) {bestFriend = newBestFriend;}
    protected:
        void notifyChangeOfAddress(const Person* oldAddress, Person* newAddress) const {
            changeOfAddressData.addressChange (oldAddress, newAddress);
            delete oldAddress;
        }
    private:
        std::string name;
        Person* bestFriend;
};
class Muslim : public Person {
    public:
        Muslim() = default;
        Muslim(const Person& person) : Person(person) {
            changeOfAddressData.registerObserver (this);
            notifyChangeOfAddress (&person, this);
        }
};
inline void AddressChangeData::notifyObservers() const {
    for (Person* x : observers) {
        if(x->getBestFriend() == oldAddress) {
            x->setBestFriend(newAddress);
        }
    }
}
int main() {
    Person *mary = new Person ("Mary"), *sandy = new Person ("Sandy");
    mary->setBestFriend (sandy);
    sandy->setBestFriend (mary);
    std::cout << "mary = " << mary << ", " << typeid(*mary).name() << std::endl;
    std::cout << "sandy = " << sandy << ", " << typeid(*sandy).name() << std::endl;
    std::cout << mary->getName() << "'s best friend is " << mary->getBestFriend()->getName() << "." << std::endl;
    std::cout << sandy->getName() << "'s best friend is " << sandy->getBestFriend()->getName() << "." << std::endl;
    Muslim* fatima = new Muslim(static_cast<Muslim>(*sandy));
    // all subscribers of changeOfAddressData notified of sandy's address change, sandy is deleted automatically
    fatima->setName("Fatima");
    std::cout << "fatima = " << fatima << ", " << typeid(*fatima).name() << std::endl;
    std::cout << mary->getName() << "'s best friend is " << mary->getBestFriend()->getName() << "." << std::endl;
    std::cout << fatima->getName() << "'s best friend is " << fatima->getBestFriend()->getName() << "." << std::endl;
    Muslim* shazia = new Muslim (static_cast<Muslim>(*mary));
    // all subscribers of changeOfAddressData notified of mary's address change, mary is deleted automatically
    shazia->setName ("Shazia");
    std::cout << "shazia = " << shazia << ", " << typeid(*shazia).name() << std::endl;
    std::cout << shazia->getName() << "'s best friend is " << shazia->getBestFriend()->getName() << "." << std::endl;
    std::cout << fatima->getName() << "'s best friend is " << fatima->getBestFriend()->getName() << "." << std::endl;
    std::cin.get();
}
相关文章: