Как я могу улучшить мою UML-моделирование следующего кода на C ++? - PullRequest
0 голосов
/ 16 мая 2019

Я моделирую базовый код на c ++ с использованием UML. У меня есть первый проект. Я хотел бы получить отзыв о том, как я могу улучшить его, или я что-то пропустил, или что-то не так с графиком.

Диаграмма UML: structural diagram

и код:

#include <ctime>
#include <functional>
#include <iostream>
#include <math.h>
#include <numeric>
#include <string>
#include <vector>


// CLASS: declaration -------------------------------------
// # Animal ...............................................
class Animal{
    private:
        std::string name;
        double height;
        double weight;

        // member of a class as static { bit.ly/2EXnDTW }
        static int numOfAnimals;
    public:
        static int GetNumOfAnimals(){return numOfAnimals;}

        void SetName(std::string name){this->name = name;} //<mutator/SETTER
        std::string GetName(){return name;} //<accessor/GETTER

        void SetHeight(double height){this->height = height;}
        double GetHeight(){return height;}

        void SetWeight(double weight){this->weight = weight;}
        double GetWeight(){return weight;}

        //note: possible not to provide a name here with your prototypes
        //ex: void SetAll(std::string, double, double);
        void SetAll(std::string name, double height, double weight);

        Animal(std::string name, double height, double weight); //<constructor
        Animal(); //<overload constructor when no attributes are passed
        ~Animal(); //<deconstructor

        void ToString();
};

int Animal::numOfAnimals = 0;

void Animal::SetAll(std::string name, double height, double weight){
    this->name = name;
    this->height = height;
    this->weight = weight;
}
//constructor
Animal::Animal(std::string name, double height, double weight){
    this->name = name;
    this->height = height;
    this->weight = weight;
    Animal::numOfAnimals++;
}
//overload constructor when no attributes are passed
Animal::Animal(){
    this->name = "";
    this->height = 0;
    this->weight = 0;
    Animal::numOfAnimals++;
}
//destructor
Animal::~Animal(){ std::cout << "Animal " << this -> name << " destroyed\n";}

void Animal::ToString(){
    std::cout << this -> name << " is "
              << this -> height << " cms tall and "
              << this -> weight << " kgs in weight\n";
}

// # Dog ..................................................
class Dog: public Animal{
    private:
        std::string sound = "woof";
    public:
        void MakeSound(){ printf("The dog %s says %s\n", this->GetName().c_str(), this->sound.c_str());}
        Dog(std::string name, double height, double weight, std::string sound);
        Dog(): Animal(){};
        void ToString();
};

Dog::Dog(std::string name, double height, double weight, std::string sound) :
Animal(name, height, weight){
    this->sound = sound;
}

void Dog::ToString(){
    //printf("%s is %d cms tall and %d kgs in weight and says %s\n",
    //        this->GetName().c_str(), this->GetHeight(), this->GetWeight(), this->sound.c_str());
    // note: do not work well with this->GetHeight() and this->GetWeight()
    std::cout << this -> GetName()   << " is "
              << this -> GetHeight() << " cms tall and "
              << this -> GetWeight() << " kgs in weight and says "
              << this -> sound       << "\n";
}

// END CLASS ----------------------------------------------

int main (int argc, char** argv) {
    //create 1st animal - fred
    Animal fred;
    //test overloaded constructor
    fred.ToString();
    //add attributes value of 1st animal - Fred
    fred.SetHeight(33);
    fred.SetWeight(10);
    fred.SetName("Fred");
    fred.ToString();
    //create 2nd animal using constructor - tom
    Animal tom("Tom", 36, 15);
    tom.ToString();
    //create 1st dog - spot
    Dog spot("Spot", 38, 16, "woofWoof");
    //print 2nd dog info
    spot.ToString();
    spot.MakeSound();
    //print number of animal
    std::cout << "Number of Animals : " << Animal::GetNumOfAnimals() << "\n";
    return 0;
}

Ожидаемый и текущий вывод кода:

  • имеет рост 0 см и вес 0 кг
  • Фред ростом 33 см и весом 10 кг
  • Том 36 см в высоту и 15 кг в весе
  • Пятно составляет 38 см в высоту и 16 кг в весе и говорит: woofWoof
  • Собачья пятно говорит: гав
  • Количество животных: 3
  • Пятно животного уничтожено
  • Животное Том уничтожено
  • Животное Фред уничтожено

1 Ответ

1 голос
/ 16 мая 2019

Наверное, лучшее место не здесь, а на https://codereview.stackexchange.com/ (только для кода)

Однако несколько замечаний:

  • код и UML-моделирование согласованы, и код может быть скомпилирован без предупреждения, что здорово

  • почему A01 : Animal вместо fred : Animal, A02 : Animal вместо tom : Animal и D01 : Dog вместо spot : Dog?

  • Обозначения на диаграмме классов для параметров операций не соответствуют стандарту UML, например, SetName(string name) : void должно быть SetName(in name : string) : void или SetName(name : string) : void, если направление скрыто.

  • Я рекомендую вам использовать const операцию, чем больше вы можете, например, для getter ( GetName , GetHeight ...)

  • в конструкторе без аргументов вам не нужно делать this->name = "";, к счастью std::string в качестве конструктора, создающего пустую строку

  • Animal::ToString() и Dog::ToString() не делают строки, пишут на стандартный вывод, их имена вводят в заблуждение

  • вы объявляете деструкторы, но не определяете их

  • потому что Животное является базовым классом, поместив его деструктор виртуальный . Это необходимо в случае, если вы удаляете экземпляр из указателя Animal , который на самом деле является экземпляром подкласса. Вы пропустили уменьшение numOfAnimals в нем.

  • Лучше иметь ToString virtual для вызова версии в зависимости от реального типа экземпляра, а не от типа, известного во время компиляции. Добавьте { Animal * a = &spot; a->ToString(); } в main и посмотрите на результат.

  • Почему вы используете printf в MakeSound()?

  • вы разрешаете создавать экземпляр Животное , это приемлемый выбор, другой слишком делает этот класс абстрактным, чтобы разрешить создавать экземпляры только подклассов, связанных с эффективными животными

  • Лично я использую символ в верхнем регистре только для начала имени операции (и атрибута), когда оно статическое , что позволяет их различать.

P.S. учитывая вашу фотографию на С.О. Я удивлен, что нет класса обезьян; -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...