Applying Abstract Factory Design Pattern in C++

瘦欲@ 提交于 2019-12-25 03:07:40

问题


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.?


回答1:


Use of

    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){

    }

is a poor implementation. A better implementation would be:

  1. Create a function to register builder functions.
  2. Register builder functions with different modes.
  3. Call the builder function given a mode.

FlightModeFactory.h:

class FlightModeFactory
{
   public:

    typedef FlightModeInterface* (*Builder)();

    static void registerBuilder(FlightModeInterface::FLIGHT_MODES mode,
                                Builder builder);

    static FlightModeInterface* build(FlightModeInterface::FLIGHT_MODES mode);
};

FlightModeFactory.cpp:

typedef std::map<FlightModeInterface::FLIGHT_MODES, FlightModeFactory::Builder> BuilderMap;

static BuilderMap& getBuilderMap()
{
   static BuilderMap builderMap;
   return builderMap;
}

void FlightModeFactory::registerBuilder(FlightModeInterface::FLIGHT_MODES mode,
                                    Builder builder)
{
   getBuilderMap()[mode] = builder;
}


FlightModeInterface* FlightModeFactory::build(FlightModeInterface::FLIGHT_MODES mode)
{
   Builder builder = getBuilderMap()[mode];
   if ( builder )
   {
      return builder();
   }
   else
   {
      // assert()??
      return nullptr;
   }
}

Now, register builder functions.

Holding.cc:

// Function to build a Holding.
static FlightModeInterface* buildHolding()
{
   return new Holding;
}

// Register the builder function.
static int registerBuilder()
{
   FlightModeInterface::registerBuilder(FlightModeInterface::FLIGHT_MODES::HOLDING,
                                     buildHolder);
   return 0;
}

static int dummy = registerBuilder();

Register similar functions for other sub-types of FlightModeInterface.




回答2:


--Iface
#pragma once
#include <iostream> 
using namespace std;

class ISmart
{
public:
    virtual string name() = 0;
};

class IDumm
{
public:
    virtual string name() = 0;
};

--------
Ifaceimpl

#pragma once
#include <iostream> 
#include "iface.h"

using namespace std;

class Asha : public IDumm
{
public:
    string name()
    {
        return "Asha";
    }
};

class Primo : public IDumm
{
public:
    string name()
    {
        return "Primo";
    }
};

class HTC4 : public IDumm
{
public:
    string name()
    {
        return "Htc4";
    }
};

class Lumia : public ISmart
{
public:
    string name()
    {
        return "Lumia";
    }
};

class Galaxy : public ISmart
{
public:
    string name()
    {
        return "Galaxy";
    }
};

class HTC8 : public ISmart
{
public:
    string name()
    {
        return "HTC8";
    }
};

AF

#pragma once
#include "iface.h"

enum phone { NOKIA = 0, SAMSUNG, HTC };

class AbstractFactory
{
public:
    virtual ISmart* getSmart() = 0;
    virtual IDumm* getDumm() = 0;
    static AbstractFactory* GetFactory(enum phone);
};

-- -

AB Impl

#include "iface_impl.h"
#include "AbstractFactory.h"

class Nokia : public AbstractFactory
{
public:

    ISmart* getSmart()
    {
        return new Lumia();
    }
    IDumm* getDumm()
    {
        return new Asha();
    }
};

class Samsung : public AbstractFactory
{
public:

    ISmart* getSmart()
    {
        return new Galaxy();
    }
    IDumm* getDumm()
    {
        return new Primo();
    }
};

class Htc : public AbstractFactory
{
public:

    ISmart* getSmart()
    {
        return new HTC8();
    }
    IDumm* getDumm()
    {
        return new HTC4();
    }
};

AbstractFactory* AbstractFactory::GetFactory(phone oem)
{
    if (NOKIA == oem)
    {
        return new Nokia;
    }
    else if (SAMSUNG == oem)
    {
        return new Samsung;
    }
    else if (HTC == oem)
    {
        return new Htc;
    }
    return 0;
}

int main()
{
    AbstractFactory* pFactory = AbstractFactory::GetFactory(NOKIA);
    cout << "Factory is " << pFactory->getSmart()->name() << endl;
    return 0;
}



Compare your program


来源:https://stackoverflow.com/questions/32800725/applying-abstract-factory-design-pattern-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!