问题
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:
- Create a function to register builder functions.
- Register builder functions with different modes.
- 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