JeroMiya
2007.07.16, 11:22 AM
As an exercise in learning java, I'm porting and rewriting/redesigning some of my old code from C++ to Java. I came across my Variable class (used in the implementation of a scripting language for the greenengine project) and it is in need of a redesign.
First, here is the original class:
/**
* This file contains the Variable class, which represents a generic
* variable in a game Entity. Variable can be an integer or a float.
* More variable types may be added in the future
*
* \file Variable.h
* \author Jeremy Bell
* \date 02-26-07
*/
#ifndef VARIABLE_H
#define VARIABLE_H
#include <iostream>
#include <boost/shared_ptr.hpp>
namespace green
{
/**
* This is the Variable class, which is used by the Entity class
* to represent custom object variables. For now, variables can
* either be integers or floating point values.
*/
class Variable
{
public:
/// This represents the type of variable it is
enum Type {FLOAT_VAR, INT_VAR};
/** This union represents the value of the variable
* I only recommend adding built-in types here, and possibly one
* string type in the future.
*/
union Value {
Value() : intVal(0) {}
Value(int ival) : intVal(ival) {}
Value(float fval) : floatVal(fval) {}
int intVal; ///< the integer value of the variable if it is an int
float floatVal; ///< the float value of the variable if it is a float
};
/** Variables default to INT_VAR types */
Variable() : mType(INT_VAR) {mValue.intVal = 0;}
/** Copy constructor from an int */
Variable(int copy) {
mType = INT_VAR;
mValue.intVal = copy;
}
/** Copy constructor from a float */
Variable(float copy) {
mType = FLOAT_VAR;
mValue.floatVal = copy;
}
/** Overloaded the == operator between Variable objects.
* \param rhs This is the right hand side of the == operation.
* \return Returns true if the two Variable objects are the same type
* and have the same value.
*/
bool operator==(const Variable& rhs) const
{
bool ret = false;
if(rhs.mType == mType)
{
switch(mType)
{
case INT_VAR:
if(mValue.intVal == rhs.mValue.intVal)
ret = true;
break;
case FLOAT_VAR:
if(mValue.floatVal == rhs.mValue.floatVal)
ret = true;
break;
}
}
return ret;
}
/** Assignment to an integer. Sets the type to INT_VAR and the value
* appropriately.
* \param value The new value of the Variable, as an integer.
* \return returns reference to *this, as per convention of = operator
*/
Variable& operator=(int value)
{
mType = INT_VAR;
mValue.intVal = value;
return *this;
}
/** Assignment to an float. Sets the type to FLOAT_VAR and the value
* appropriately.
* \param value The new value of the Variable, as a float.
* \return returns reference to *this, as per convention of = operator
*/
Variable& operator=(float value)
{
mType = FLOAT_VAR;
mValue.floatVal = value;
return *this;
}
/** Print the Variable to a std::ostream. Also prints the type of the
* Variable for easy reading. May provide a bare print method in the
* future if necessary.
* \param os The output stream to print the variable to.
*/
void Print(std::ostream& os) const
{
// os << "Type: ";
// switch(mType)
// {
// case INT_VAR:
// os << "INT_VAR VALUE: " << mValue.intVal;
// break;
// case FLOAT_VAR:
// os << "FLOAT_VAR VALUE: " << mValue.floatVal;
// break;
// }
}
/** Default constructor defined as virtual */
virtual ~Variable() {}
/** Get the type of variable it is */
inline Variable::Type GetType() const { return mType; }
/** Set the type of variable this is
* \param type The new type of variable
*/
inline void SetType(Variable::Type type) { mType = type; }
/** Get the value of the variable */
inline Variable::Value GetValue() const { return mValue; }
/** Set the value of the variable
* \param value The new value of the variable
*/
inline void SetValue(Variable::Value value) {mValue = value; }
/** Set the value of the variable to an int
* \param value The new value of the variable
*/
inline void SetValue(int value) { *this = value; }
/** Set the value of the variable to a float
* \param value The new value of the variable
*/
inline void SetValue(float value) { *this = value; }
private:
Variable::Value mValue; ///< the value of the variable
Variable::Type mType; ///< the type of the variable
};
typedef boost::shared_ptr<Variable> VariablePtr;
/** Overload the << operator for std::ostream and Variable. Uses
* Variable::Print internally.
* \param lhs The output stream to Print to.
* \param rhs The Variable to Print.
*/
inline
std::ostream& operator<<(std::ostream& lhs, const Variable& rhs)
{
rhs.Print(lhs);
return lhs;
}
/** Overload the << operator for std::ostream and Variable::Type
* \param lhs The output stream to print to.
* \param rhs The Variable::Type to print
*/
inline
std::ostream& operator<<(std::ostream& lhs, const Variable::Type& rhs)
{
switch(rhs)
{
case Variable::INT_VAR:
lhs << "INT_VAR";
break;
case Variable::FLOAT_VAR:
lhs << "FLOAT_VAR";
break;
default:
lhs << "Unknown Variable::Type";
break;
}
lhs << std::flush;
return lhs;
}
/** Overload the << operator for std::ostream and Variable::Value
* \param lhs The output stream to print to.
* \param rhs The Variable::Value to print
*/
inline
std::ostream& operator<<(std::ostream& lhs, const Variable::Value& rhs)
{
lhs << "(" << rhs.intVal << ", " << rhs.floatVal << ")" << std::flush;
return lhs;
}
/** Print a Variable::Value based on a Variable::Type
* \param value the value to print
* \param type the type of value to print
* \param os The ostream to print to
*/
inline
void PrintValue(const Variable::Value& value, Variable::Type type, std::ostream& os)
{
switch(type)
{
case Variable::INT_VAR:
os << value.intVal;
break;
case Variable::FLOAT_VAR:
os << value.floatVal;
break;
default:
os << "unknown Variable::Type" << std::endl;
break;
}
}
}
#endif
Now, as you can see, it uses a union type to store the value of the variable, and an enum type to store the type of the variable (in this case, just INT or FLOAT). This design has been somewhat problematic elsewhere in the project.
Does anyone have any suggestions for redesigning this class in Java?
-JeroMiya
edit: Don't ask why I'm implementing my own scripting language instead of using an existing one. This project is a class project. I was told to do it this way.
First, here is the original class:
/**
* This file contains the Variable class, which represents a generic
* variable in a game Entity. Variable can be an integer or a float.
* More variable types may be added in the future
*
* \file Variable.h
* \author Jeremy Bell
* \date 02-26-07
*/
#ifndef VARIABLE_H
#define VARIABLE_H
#include <iostream>
#include <boost/shared_ptr.hpp>
namespace green
{
/**
* This is the Variable class, which is used by the Entity class
* to represent custom object variables. For now, variables can
* either be integers or floating point values.
*/
class Variable
{
public:
/// This represents the type of variable it is
enum Type {FLOAT_VAR, INT_VAR};
/** This union represents the value of the variable
* I only recommend adding built-in types here, and possibly one
* string type in the future.
*/
union Value {
Value() : intVal(0) {}
Value(int ival) : intVal(ival) {}
Value(float fval) : floatVal(fval) {}
int intVal; ///< the integer value of the variable if it is an int
float floatVal; ///< the float value of the variable if it is a float
};
/** Variables default to INT_VAR types */
Variable() : mType(INT_VAR) {mValue.intVal = 0;}
/** Copy constructor from an int */
Variable(int copy) {
mType = INT_VAR;
mValue.intVal = copy;
}
/** Copy constructor from a float */
Variable(float copy) {
mType = FLOAT_VAR;
mValue.floatVal = copy;
}
/** Overloaded the == operator between Variable objects.
* \param rhs This is the right hand side of the == operation.
* \return Returns true if the two Variable objects are the same type
* and have the same value.
*/
bool operator==(const Variable& rhs) const
{
bool ret = false;
if(rhs.mType == mType)
{
switch(mType)
{
case INT_VAR:
if(mValue.intVal == rhs.mValue.intVal)
ret = true;
break;
case FLOAT_VAR:
if(mValue.floatVal == rhs.mValue.floatVal)
ret = true;
break;
}
}
return ret;
}
/** Assignment to an integer. Sets the type to INT_VAR and the value
* appropriately.
* \param value The new value of the Variable, as an integer.
* \return returns reference to *this, as per convention of = operator
*/
Variable& operator=(int value)
{
mType = INT_VAR;
mValue.intVal = value;
return *this;
}
/** Assignment to an float. Sets the type to FLOAT_VAR and the value
* appropriately.
* \param value The new value of the Variable, as a float.
* \return returns reference to *this, as per convention of = operator
*/
Variable& operator=(float value)
{
mType = FLOAT_VAR;
mValue.floatVal = value;
return *this;
}
/** Print the Variable to a std::ostream. Also prints the type of the
* Variable for easy reading. May provide a bare print method in the
* future if necessary.
* \param os The output stream to print the variable to.
*/
void Print(std::ostream& os) const
{
// os << "Type: ";
// switch(mType)
// {
// case INT_VAR:
// os << "INT_VAR VALUE: " << mValue.intVal;
// break;
// case FLOAT_VAR:
// os << "FLOAT_VAR VALUE: " << mValue.floatVal;
// break;
// }
}
/** Default constructor defined as virtual */
virtual ~Variable() {}
/** Get the type of variable it is */
inline Variable::Type GetType() const { return mType; }
/** Set the type of variable this is
* \param type The new type of variable
*/
inline void SetType(Variable::Type type) { mType = type; }
/** Get the value of the variable */
inline Variable::Value GetValue() const { return mValue; }
/** Set the value of the variable
* \param value The new value of the variable
*/
inline void SetValue(Variable::Value value) {mValue = value; }
/** Set the value of the variable to an int
* \param value The new value of the variable
*/
inline void SetValue(int value) { *this = value; }
/** Set the value of the variable to a float
* \param value The new value of the variable
*/
inline void SetValue(float value) { *this = value; }
private:
Variable::Value mValue; ///< the value of the variable
Variable::Type mType; ///< the type of the variable
};
typedef boost::shared_ptr<Variable> VariablePtr;
/** Overload the << operator for std::ostream and Variable. Uses
* Variable::Print internally.
* \param lhs The output stream to Print to.
* \param rhs The Variable to Print.
*/
inline
std::ostream& operator<<(std::ostream& lhs, const Variable& rhs)
{
rhs.Print(lhs);
return lhs;
}
/** Overload the << operator for std::ostream and Variable::Type
* \param lhs The output stream to print to.
* \param rhs The Variable::Type to print
*/
inline
std::ostream& operator<<(std::ostream& lhs, const Variable::Type& rhs)
{
switch(rhs)
{
case Variable::INT_VAR:
lhs << "INT_VAR";
break;
case Variable::FLOAT_VAR:
lhs << "FLOAT_VAR";
break;
default:
lhs << "Unknown Variable::Type";
break;
}
lhs << std::flush;
return lhs;
}
/** Overload the << operator for std::ostream and Variable::Value
* \param lhs The output stream to print to.
* \param rhs The Variable::Value to print
*/
inline
std::ostream& operator<<(std::ostream& lhs, const Variable::Value& rhs)
{
lhs << "(" << rhs.intVal << ", " << rhs.floatVal << ")" << std::flush;
return lhs;
}
/** Print a Variable::Value based on a Variable::Type
* \param value the value to print
* \param type the type of value to print
* \param os The ostream to print to
*/
inline
void PrintValue(const Variable::Value& value, Variable::Type type, std::ostream& os)
{
switch(type)
{
case Variable::INT_VAR:
os << value.intVal;
break;
case Variable::FLOAT_VAR:
os << value.floatVal;
break;
default:
os << "unknown Variable::Type" << std::endl;
break;
}
}
}
#endif
Now, as you can see, it uses a union type to store the value of the variable, and an enum type to store the type of the variable (in this case, just INT or FLOAT). This design has been somewhat problematic elsewhere in the project.
Does anyone have any suggestions for redesigning this class in Java?
-JeroMiya
edit: Don't ask why I'm implementing my own scripting language instead of using an existing one. This project is a class project. I was told to do it this way.