samedi 26 septembre 2015

Applying Abstract Factory Design Pattern in C++

I have a program where user enters the operations of a plane. User can select as many operations (holding, straight, landing etc.) as s/he wants. User can calculate the necessary fuel intake with operation 5.

I have decided to apply Abstract Factory Design Pattern to my code. Here is the current version of the code without pattern is applied:

#include <iostream>
#include <stdio.h>
using namespace std;

class FlyingMode {

   protected:

    float time, fuel_rate, start, end, pace, distance;
    float total;

   public:
      FlyingMode(float _time=0, float _fuel_rate=0, float _start=0,
              float _end=0, float _pace=0, float _distance=0){

         time = _time;
         fuel_rate = _fuel_rate;
         start = _start;
         end = _end;
         pace = _pace;
         distance = _distance;
         total = 0;
     }

      virtual ~FlyingMode() {}

      virtual float calcFuel(){
         return 0;
      }
};

class Holding: public FlyingMode{

   public:
      Holding(float _time=0, float _fuel_rate=0, float _start=0,
              float _end=0, float _pace=0, float _distance=0)
              :FlyingMode(_time, _fuel_rate, _start, _end, _pace, _distance) { }

      float calcFuel(){
         total = (time * fuel_rate * 60);
         return total;
      }
};

class Raising: public FlyingMode{

   public:
      Raising(float _time=0, float _fuel_rate=0, float _start=0,
              float _end=0, float _pace=0, float _distance=0)
              :FlyingMode(_time, _fuel_rate, _start, _end, _pace, _distance) { }

      float calcFuel (){
          if(start < end && pace != 0 ){
              float rising_time = (end - start)/pace;
              total = rising_time * fuel_rate;
              return total;
          }else{
              return 0;
          }
      }
};

class Landing: public FlyingMode{

   public:
      Landing(float _time=0, float _fuel_rate=0, float _start=0,
              float _end=0, float _pace=0, float _distance=0)
              :FlyingMode(_time, _fuel_rate, _start, _end, _pace, _distance) { }

      float calcFuel (){

          if(start > end && pace != 0 ){
              float landing_time = (start - end)/pace;
              total =  landing_time * fuel_rate;
              return total;
          }else{
              return 0;
          }

      }
};

class Straight: public FlyingMode{

   public:
      Straight(float _time=0, float _fuel_rate=0, float _start=0,
              float _end=0, float _pace=0, float _distance=0)
              :FlyingMode(_time, _fuel_rate, _start, _end, _pace, _distance) { }

      float calcFuel (){

          if(distance != 0 || pace != 0 ){
              float straight_time = distance/pace;
              total = straight_time * fuel_rate;
              return total;
          }else{
              return 0;
          }
      }
};

// Main function for the program
int main( ){

    char op = 's';
    float time=0, fuel_rate=0, start=0, end=0, pace=0, distance=0;
    float total = 0;

    while(op != 'x') {
        FlyingMode *mode;
        Holding hold;
        Raising raise;
        Landing land;
        Straight straight;

        float hold_result, raise_result, land_result, str_result;

        cout << "Please select an operation: " << endl;
        cout << "1 ---> Holding flight" << endl;
        cout << "2 ---> Raising" << endl;
        cout << "3 ---> Landing " << endl;
        cout << "4 ---> Straight " << endl;
        cout << "5 ---> Calculate total fuel consumption" << endl;
        cout << "x ---> Exit " << endl;

        cin >> op;

        switch(op){
        case '1':
            cout << "Holding time (minutes): ";
            cin >> time;
            cout << "Fuel rate (kg/sec): ";
            cin >> fuel_rate;

            //call holding fuel
            hold = Holding(time, fuel_rate, 0, 0, 0, 0);
            mode = &hold;

            hold_result = mode -> calcFuel();
            total += hold_result;
            break;
        case '2':
            cout << "Enter starting altitude of raising (meters): ";
            cin >> start;
            cout << "Enter ending altitude of raising (meters):";
            cin >> end;
            cout << "Enter raising pace (meter/sec): ";
            cin >> pace;
            cout << "Fuel rate (kg/sec): ";
            cin >> fuel_rate;

            raise = Raising(0, fuel_rate, start, end, pace, 0);
            //call raising fuel
            mode = &raise;

            raise_result = mode -> calcFuel();
            total += raise_result;
            break;
        case '3':
            cout << "Enter starting altitude of landing (meters): ";
            cin >> start;
            cout << "Enter ending altitude of landing (meters):  ";
            cin >> end;
            cout << "Enter landing pace (meter/sec):  ";
            cin >> pace;
            cout << "Fuel rate (kg/sec):  ";
            cin >> fuel_rate;

            land = Landing(0, fuel_rate, start, end, pace, 0);
            //call landing fuel
            mode = &land;
            land_result = mode
                    -> calcFuel();
            total += land_result;
            break;
        case '4':
            cout << "Enter distance for straight flight (meters): ";
            cin >> distance;
            cout << "Enter flight pace (meter/sec): ";
            cin >> pace;
            cout << "Fuel rate (kg/sec): ";
            cin >> fuel_rate;

            straight = Straight(0, fuel_rate, 0, 0, pace, distance);
            //call straight fuel
            mode = &straight;

            str_result = mode -> calcFuel();
            total += str_result;
            break;
        case '5':
            cout <<"Total fuel requirement: "<< total << " kg"<< endl;
            total = 0;
            break;
        case 'x':
            return 0;
        default:
            continue;
        }
    }
    return 0;
}

I'm a bit confused for the application of the Abstract Factory Design. So far I have created these classes:

FlightModeInterface.h

class FlightModeInterface{

protected:
float time, fuel_rate, start, end, pace, distance;
float total;

public:
    enum FLIGHT_MODES{
        HOLDING,
        RAISING,
        LANDING,
        STRAIGHT
    };

    FlightModeInterface(float, float, float,
              float, float, float);

    virtual ~FlightModeInterface(){ }

    virtual float calcFuel() = 0;

    static FlightModeInterface* createFactory(FLIGHT_MODES);
};

Holding.h

class Holding: public FlightModeInterface{
public:

    Holding(float _time=0, float _fuel_rate=0, float _start=0,
            float _end=0, float _pace=0, float _distance=0)
            :FlightModeInterface(_time, _fuel_rate, _start, _end, _pace, _distance){ };

    virtual float calcFuel(){
        total = (time * fuel_rate * 60);
        return total;
    }
};

Landing.h

class Landing: public FlightModeInterface{

    public:

        Landing(float _time=0, float _fuel_rate=0, float _start=0,
                float _end=0, float _pace=0, float _distance=0)
                :FlightModeInterface(_time, _fuel_rate, _start, _end, _pace, _distance){ };

        virtual float calcFuel (){
            if(start > end && pace != 0 ){
                float landing_time = (start - end)/pace;
                total =  landing_time * fuel_rate;
                return total;
            }else{
                return 0;
            }
        }
    };

Raising.h

class Raising: public FlightModeInterface{
public:

    Raising(float _time=0, float _fuel_rate=0, float _start=0,
            float _end=0, float _pace=0, float _distance=0)
            :FlightModeInterface(_time, _fuel_rate, _start, _end, _pace, _distance){ };

    virtual float calcFuel (){

        if(start < end && pace != 0 ){
            float rising_time = (end - start)/pace;
            total = rising_time * fuel_rate;
            return total;
        }else{
            return 0;
        }
    }
};

Straight.h

class Straight: public FlightModeInterface{
public:

    Straight(float _time=0, float _fuel_rate=0, float _start=0,
            float _end=0, float _pace=0, float _distance=0)
            :FlightModeInterface(_time, _fuel_rate, _start, _end, _pace, _distance){ };

    virtual float calcFuel (){
        if(distance != 0 || pace != 0 ){
            float straight_time = distance/pace;
            total = straight_time * fuel_rate;
            return total;
        }else{
            return 0;
        }
    }
};

FlightModeFactory.cpp

class FlightModeFactory{
public:
    static FlightModeInterface* createFactory(FlightModeInterface::FLIGHT_MODES mode){

        if(mode == FlightModeInterface::FLIGHT_MODES::HOLDING){
            //HOW TO FILL???
        }
        else if(mode == FlightModeInterface::FLIGHT_MODES::LANDING){

        }
        else if(mode == FlightModeInterface::FLIGHT_MODES::RAISING){

        }else if(mode == FlightModeInterface::FLIGHT_MODES::STRAIGHT){

        }

    }
};

As you can see, I got confused with how to fill the if-else statements in FlightModeFactory.cpp. Any ideas on how to continue to Factory Design Pattern from this point? Is it correct to fill the calcFuel methods in Holding.h, Landing.h etc.?

Aucun commentaire:

Enregistrer un commentaire