Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Lets say I have a Enemy class, and the constructor would look something like:

public Enemy(String name, float width, float height, Vector2 position, 
             float speed, int maxHp, int attackDamage, int defense... etc.){}

This looks bad because the constructor has so many parameters, but when I create an Enemy instance I need to specify all of these things. I also want these attributes in the Enemy class, so that I can iterate through a list of them and get/set these parameters. I was thinking maybe subclassing Enemy into EnemyB, EnemyA, while hardcoding their maxHp, and other specific attributes, but then I'd lose access to their hardcoded attributes if I wanted to iterate through a list of Enemy (consisting of EnemyA's, EnemyB's, and EnemyC's).

I'm just trying to learn how to code cleanly. If it makes a difference, I work in Java/C++/C#. Any point in the right direction is appreciated.

share|improve this question
5  
There is nothing bad about having one constructor that binds all attributes. In fact, in some persistence environments, it is required. Nothing says you can't have multiple constructors, perhaps with validity checking method to be called after doing the piece-wise construction. –  BobDalgleish Mar 10 at 19:08
1  
I'd have to question if you ever intend to construct Enemy objects in code using literals. If you don't, and I don't see why you would, then build constructors that pull the data from a database interface, or a serialization string, or ... –  Zan Lynx Mar 11 at 19:01
    
Named Parameter idiom –  Mooing Duck Mar 11 at 20:29

5 Answers 5

up vote 53 down vote accepted

The solution is to bundle up the parameters into composite types. Width and Height are conceptually related - they specify the dimensions of the enemy and will usually be needed together. They could be replaced with a Dimensions type, or perhaps a Rectangle type that also includes the position. On the other hand, it might make more sense to group position and speed into a MovementData type, especially if acceleration later enters the picture. From context I assume maxHp, attackDamage, defense, etc also belong together in a Stats type. So, a revised signature might look something like this:

public Enemy(String name, Dimensions dimensions, MovementData movementData, Stats stats)

The fine details of where to draw the lines will depend on the rest of your code and what data is commonly used together.

share|improve this answer
20  
I would also add that having so many values might indicate violation of Single Responsibility Principle. And grouping values into specific objects is first step into separating those responsibilities. –  Euphoric Mar 10 at 19:53
2  
I don't think that the list of values is a SRP problem; most of them are probably intended for base class constructors. Each class in the hierarchy can have a single responsibility. Enemy is just the class that targets the Player, but their common base class Combatant needs the fight stats. –  MSalters Mar 11 at 13:16
    
@MSalters It doesn't necessarily indicate an SRP problem, but it could. If he needs to do enough number-crunching, those functions could find their way into the Enemy class when they should either be static/free functions (if he uses Dimensions/MovementData as plain old data containers) or methods (if he turns them into abstract data types/objects). As an example, if he hadn't already created a Vector2 type, he might've ended up doing vector math in Enemy. –  Doval Mar 12 at 11:30

You might want to take a look at the Builder pattern. From the link (with an examples of the pattern versus alternatives):

[The] Builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters, especially if most of those parameters are optional. Client code is much easier to read and write with builders than with the traditional telescoping constructor pattern, and builders are much safer than JavaBeans.

share|improve this answer
3  
A short code snippet would be helpful. This is a great pattern for building complicated objects or structures with various inputs. You could also specialize the builders, as EnemyABuilder, EnemyBBuilder, etc. that encapsulate the various shared properties. This is kind of the flip side of the Factory pattern (as answered below), but my personal preference is for Builder. –  Rob Y Mar 10 at 19:28
1  
Thanks, both the Builder pattern and Factory patterns look like they'd work well with what I'm trying to do overall. I think a combination of Builder/Factory and Doval's suggestion might be what I'm looking for. Edit: I guess I can only mark one answer; I'll give it to Doval since it answers the topic question, but the others are equally as helpful to my specific problem. Thank you all. –  Mark16 Mar 10 at 22:30
    
I think it is worth noting that if your language supports phantom types, then you can write a builder pattern that enforces that some/all of the SetX functions get called. It also allows one to ensure that they get called only once too (if desired). –  Thomas Eding Mar 10 at 23:23
1  
@Mark16 As mentioned in the link, > The Builder pattern simulates named optional parameters as found in Ada and Python. You mentioned you also use C# in the question, and that language does support named/optional arguments (as of C# 4.0), so that may be another option. –  Bob Mar 11 at 4:25

Using subclasses to preset some values is not desirable. Only subclass when a new type of enemy has different behavior or new attributes.

The factory pattern is usually used to abstract over the exact class used, but it can also be used to provide a templates for object creation:

class EnemyFactory {

    // each of these methods is essentially a template for a kind of enemy

    Enemy enemyA(String name, ...) {
        return new Enemy(name, ..., presetValue, ...);
    }

    Enemy enemyB(String name, ...) {
        return new Enemy(name, ..., otherValue, ...);
    }

    Enemy enemyC(String name, ...) {
        return new EnemySubclass(name, ..., otherValue, ...);
    }

    ...
}

EnemyFactory factory = new EnemyFactory();
Enemy a = factory.enemyA("fred", ...);
Enemy b = factory.enemyB("willy", ...);
share|improve this answer

I would reserve sub classing to classes that represent object that you might want to independently use, e.g. character class where all characters, not just enemies have name, speed, maxHp, or a class to represent sprites that have a presence on screen with width, height, position.

I don't see anything inherently wrong with a constructor with a lot of input parameters but if you want to split it up a bit then you could have one constructor that sets up most of the parameters and another (overloaded) constructor that can be used to set specific ones and have others set to default values.

Depending on what language you choose to use, some can set default values for the input parameters of your constructor like:

Enemy(float height = 42, float width = 42);
share|improve this answer

A code example to add to Rory Hunter's answer (in Java):

public class Enemy{
   private String name;
   private float width;
   ...

   public static class Builder{
       private Enemy instance;

       public Builder(){
           this.instance = new Enemy();
       }


       public Builder withName(String name){
           instance.name = name;
           return this;
       }

       ...

       public Enemy build(){
           return instance;
       }
   }
}

Now, you can create new instances of Enemy like this:

Enemy myEnemy = new Enemy.Builder().withName("John").withX(x).build();
share|improve this answer
1  
Programmers is tour conceptual questions and answers are expected to explain things. Throwing code dumps instead of explanation is like copying code from IDE to whiteboard: it may look familiar and even sometimes be understandable, but it feels weird... just weird. Whiteboard doesn't have compiler –  gnat Mar 11 at 14:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.