views:

340

answers:

11

I want to see if anyone has a better design for a class (class as in OOP) I am writing. We have a script that puts shared folder stats in an csv file. I am reading that in and putting it in a Share class.

My Boss wants to know information like:

  • Total Number of Files
  • Total Size of Files
  • Number of Office Files
  • Size of Office Files
  • Number of Exe Files
  • Size of Exe Files
  • etc ....

So I have a class with variables like $numOfficeFiles and $sizeOfficeFiles etc. with a ton of get/set methods. Isn't there a better way to do this? What is the general rule if you have a class with a lot of variables/properties?

I think of this as a language agnostic question but if it matters, I am using PHP.

+1  A: 

I think the answer is "there's no such thing as too many variables."

But then, if this data is going to be kept for a while, you might just want to put it in a database and make your functions calls to the database.

I assume you don't want to recalculate all these values every time you're asked for them.

there definitely is such a thing as too many variables - cf. god classes, cf. stackOverflowException
annakata
+1  A: 

Each class' "max variables" count really is a function of what data makes sense for the class in question. If there are truly X different values for a class and all data is related, that should be your structure. It can be a bit tedious to create depending on the language being used, but I wouldn't say there is any "limit" that you shouldn't exceed. It is dictated by the purpose.

Mitchel Sellers
+3  A: 

"A class should do one thing, and do it well"

If you're not breaking this rule, then I'd say there aren't too many.

However it depends.

If by too many you mean 100's, then you might want to break it into a data class and collection as shown in the edit below.

Then you've only one get/set operation, however there are pros and cons to this "lazyness".

EDIT:

On second glance, you've pairs of variables, Count and Size. There should be another class e.g. FileInfo with count and class, now your frist class just has FileInfo classes.

You can also put file type e.g. "All", "Exe" . . . on the File Info class. Now the parent class becomes a collection of FileInfo objects.

Personally, I think I'd go for that.

Binary Worrier
I think variables vs dictionary should be tied to the sparseness of the object. If you use a dictionary on a class that will never have a blank field, you're just wasting space and introducing bug potential.In this case, I'd say the data isn't sparse enough for that.
CMartin: I wasn't happy with the dictionary myself, changed the answer to have a neater alternative
Binary Worrier
A: 

There is no "hard" limit. OO design does however have a notion of coupling and cohesion. As long as your class is loosely coupled and highly cohesive I believe that you are ok with as many members/methods as you need.

Matt Campbell
A: 

just From what I glanced at.

If you keep an array with all of the file names in it, All of those variables can be computed on the fly.

J.J.
A: 

Maybe I didn't understand the goal, but why do you load all the values into memory by using the variables, just to dump them to the csv file (when?). I'd prefer a stateless listener to the directory and writing values immediately to the csv.

Kai
My guess is that there is a high probability of the boss coming up with some more requirements in the future that require some business logic to be coded.
moffdub
+8  A: 

sometimes, data can be just data

files = { 
   'total':  { count: 200, size: 3492834 }, 
   'office': { count: 25, size: 2344 },
   'exe':    { count: 30, size: 342344 },
   ...
}
Jimmy
Jimmy, what language is that?
Binary Worrier
Although I don't recognize your language example either, I TOTALLY agree about let data be data. Put it into a hash. NEVER make a class that doesn't have business logic methods. You may then have a class that manipulates your data...
Bill K
ok, you caught me, I like to type out random symbols for no reason. removed the extraneous '>' to yield Javascript.
Jimmy
A: 

It's more of a readability isue.

I would wrap all the data into array. And use just one pair of get/set methods

Something like:

class Test() {

private $DATA = array();

function set($what,$data) {
   $DATA[$what] = $data;
}
function get($what) {
 return $this->DATA[$what];
}

}

Maiku Mori
A: 

I always try to think of a Class as being the "name of my container" or the "name of the task" that I am going to compute. Methods in the Class are "actions" part of the task.

In this case seems like you can start grouping things together, for example you are repeating the number and the size actions many times. Why not create a super class that other classes inherit from, for example:

class NameOfSuperClass {
    public $type;
    function __construct($type) {
        $this->type = $type;
        $this->getNumber();
        $this->getSize();
    }
    public function getNumber() {
        // do something with the type and the number
    }
    public function getSize() {
        // do something with the type and the size
    }
}

Class OfficeFiles extends NameOfSuperClass {
    function __construct() {
        $this->_super("office");
    }
}

I'm not sure if this is right in PHP, but you get my point. Things will start to look a lot cleaner and better to manage.

Luca Matteis
+1  A: 

Sounds like you might have a ton of duplicate code. You want the # of files and the size of files for a bunch of different types. You can start with a class that looks like this:

public class FileStats
{
    public FileStats(String extension)
    {
        // logic to discover files goes here
    }

    public int getSize() { }
    public int getNumFiles() { }
}

Then, in your main class, you can have an array of all the file types you want, and a collection of these helper objects:

public class Statistics
{
    private static final String[] TYPES = { "exe", "doc", "png" };
    private Collection<FileStats> stats = new HashSet<FileStats>();

    public static void collectStats()
    {            
        stats.clear();
        for(String type : TYPES)
            stats.add(new FileStats(type));
    }
}

You can clean up your API by passing a parameter to the getter method:

public int getNumFiles(String type)
{
    return stats.get(type).getNumFiles();
}
Outlaw Programmer
+6  A: 

I voted up a couple good answers, but I wanted to add that whenever I see more than 5 or 6 non-final variables in a class I get antsy.

Chances are that they should probably be placed in a smaller class as suggested by Outlaw Programmer. There's also a good chance it could just be placed in a hashtable.

Here's a good rule of thumb, if you have a variable that has nothing but a setter and a getter, you have DATA not code--get it out of your class and place it into a collection or something.

Having variable with a setter and a getter just means that either you never do anything with it (it's data) or the code that manipulates it is in another class (terrible OO design, move the variable to the other class).

Remember--every piece of data that is a class member is something you will have to write specific code to access; for instance, when you transfer it from your object to a control on a GUI.

I often tag GUI controls with a name so I can iterate over a collection and automatically transfer data from the collection to the screen and back, significantly reducing boilerplate code; storing the data as member variables makes this process much more complicated (requires reflection).

Bill K
+1 for bashing brainless getters and setters, and for hash table love. I've been using them more and more, and every time I do, I feel a little less guilty.
moffdub