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.

I want to illustrated my question by way of a (hopefully) representative example.

Lets say I have a situation where I am developing a class library in C# to be used in some simulations. I want to define the planets (Earth, Mars, Saturn, etc.) and have each of them have some properties and methods that are common in interface (name, signature, etc.) but unique in implementation per-each. I.e. Earth.Mass is not equal to Mars.Mass.

So far no big deal.

I want to have some other classes/methods/algorithm that accept as an argument a planet and use its defined properties and method:

double MyApparentWeight(Planet someplanet, double MassInKG)
double DistanceFromInKM(Planet someplanet, Planet originplanet)

Planets could be used all over the place by someone using this library. All "Earth"s should be identical and all "Saturn"s should be identical. Obviously the "Earth"s are distinct from the "Saturn"s.

I also want a user of the library to be able to easily create a new planet (e.g. Vulcan, Endor, Tralfamadore, Persephone, Rupert, etc.). It should be forced to supply the properties and methods of the existing ones and hence be useable by the MyApparentWeight and DistanceFromInKM methods.

So the base level approach is that there is a Planet class and then the specific ones (Earth, Vulcan, etc.) simply inherit from that. In this case though a user needs to either create an instance of Earth and carry it around or create a new one every time it is needed. That could be unnecessarily clunky (especially in light of the expected users) and possibly a performance hit since some Planets could have initialization steps of reading date from files, etc.

The next idea was the above but with a singleton paradigm. That's basically what I've done so far. This seems to be dictating internal implementation to any new Planets that are created (and again some what of a concern given the potential level of some users).

This project is how I've been cutting my C#/.NET teeth. My initial naive approach was to try to do static classes with interfaces or inheritance. Obviously I learned quickly the folly of that path. At a high level that is the kind of paradigm I would have wanted though.

Is there some other design pattern that I'm missing that could cover this type of situation?

Appreciate any suggestions.

Updates

I may not have made it clear that this Planet example was only meant to be illustrative structurally and not directly representative of the actual computations. Some people seemed to get a little wrapped up in the implementations of what data is being represented within them and other peripheral aspects.

The suggestions of the individual planets (like Earth) merely being instances of the Planet class didn't catch my points about potentially significant different implementations for their internal mechanics supporting their methods and properties. I'm also at a loss as to how it helps with not wanting to manage carrying around those instances potentially anywhere you may want to use them or having to create new instances.

Glenn's extension of Stephen's suggestion I think actually works the best in the context of what I need here. I can couple that with rsbarro's suggestion of having static properties for the built in Planet children. (Actually more like interface IPlanet implementers). That provides the easiest access for the users for the most commonly used items and offers a slight performance improvement of not having to retrieve from the dictionary by name each time. It still offers the ability for the users to dynamically add more types of Planets.

I don't yet have the rep to up-vote all of the answers I mentioned above or I would.

Thank you all for your suggestions and feedback.

share|improve this question

migrated from stackoverflow.com Mar 27 at 0:34

This question came from our site for professional and enthusiast programmers.

5  
It sounds like your actual planets are just instances of Planet. Are they actually derived classes, and if so, why? You could define a namespace that gives access to your specific instances, but also have a set of user-defined planets (indexed by name so that they are unique). –  AndyG Mar 27 at 0:31
    
@andyg: I agree. Inheritance is not the answer. They're all just planets with different data. So far as is given, this is a question about structuring data, not code. –  david.pfx Mar 27 at 5:20
    
Interestingly, I might suggest MEF's composition container for this. If you export each planet with a name, the instances are kept separate and somewhat static; if you're careful, you'll never deal with them statically or as singletons, but you'll still have only one of each planet. –  Magus Mar 27 at 14:35
    
OP: Are you really asking for how to choose one of many classes, which may have different behavior, or one or more data-objects? –  DougM Mar 27 at 19:32
    
DougM: They are classes with the same sets of methods and properties but the underlying algorithms (i.e. behaviors) are different. –  kcc Mar 28 at 22:27

6 Answers 6

up vote 1 down vote accepted

I would have a generic planet class, with read-only properties that were set by constructor parameters.

class Planet
{
    public string Name { get; private set; }
    public double Mass { get; private set; }

    public Planet(string name, double mass)
    {
        this.Name = name;
        this.Mass = mass;
    }
}

I would then have a PlanetFactory class for generating well known planets:

static class PlanetFactory
{
    public static Planet CreateEarth() 
    { 
        return new Planet("Earth", 597219000000000000000000); 
    }

    public static CreateByName(string name)
    {
        if (name.Equals("Earth")) return CreateEarth();
    }
}

I would then have a manager class to hold all of your planets:

class PlanetManager
{
    private Dictionary<string, Planet> planets;

    public GetPlanet(string name)
    {
        if (!planets.ContainsKey(name))
        {
            planets.add(name, PlanetFactory.CreateByName(name));
        }

        return planets[name];
    }
}

This approach means that you can easily add new well-known planets and provide a mechanism for adding new planets through the PlanetManager class (though you would need a different method to do so).

share|improve this answer
    
IMO this is close to the best answer provided, except that I'd use an ENUM instead of magic strings and I'd override Dictionary<enum, planet> and lazily create them on get. Posted as such. +1 –  Steve Evers Mar 27 at 22:04
    
The issue with doing things based on an enum is that it doesn't give a ready way for the users to add new planets to the list that aren't there at compile time. –  kcc Mar 28 at 22:24

You could make static properties on Planet for each of the specific planets you want to create.

For example:

public class Planet
{
    public string Name { get; set; }
    public double Mass { get; set; }

    private static Planet _earth;
    public static Planet Earth { get { return GetEarth(); } }

    //Use this approach so that you only create a planet if it is needed
    private static Planet GetEarth()
    {
         if(_earth == null)
              _earth = new Planet { Name = "Earth", Mass = 123.0 };
         return _earth;
    }
}

This approach is similar to how the System.Drawing.Color class works. Take a look at that in ILSpy, specifically the named color properties like Aqua, White, etc.

share|improve this answer
1  
better to make constructor private –  Bryan Chen Mar 27 at 1:00
    
If the constructor is made private, then you'll need to provide a way for a user to create a new planet by adding a static method CreatePlanet onto the Planet class, similar to how Color has a FromArgb method. –  rsbarro Mar 27 at 13:51

I would use a solution similiar to Stephens, in that it involves a dictionary and PlanetManager is static.

This example assumes that you already have a base Planet type and subclasses of Planet (such as Earth) for different planets. This would also work for planetary implementations without subclassing (as in all planets are instances of Planet and not a derived class). If you are extending Planet to create all of your planets, I recommend making Planet abstract so that it must be extended to create instances.

public static class PlanetManager
{
    static PlanetManager()
    {
        // Initialize the planets dictionary in a static constructor
        _planets = new Dictionary<string, Planet>();
        // Add existing planets to the dictionary using the appropriate constructor
        _planets.Add("earth", new Earth());
    }

    private static Dictionary<string, Planet> _planets;

    public static void AddPlanet(string name, Planet planet)
    {
        if(name == null)
        {
            throw new ArgumentNullException("name");
        }

        if(planet == null)
        {
            throw new ArgumentNullException("planet");
        }

        if(_planets.ContainsKey(name.ToLower()))
        {
            // Only one planet per name
            throw new InvalidOperationException("That planet already exists.");
        }

        // Add the planet to the dictionary
        _planets[name.ToLower()] = planet;
    }

    public static Planet GetPlanet(string name)
    {
        if(name == null)
        {
            // Null checks
            throw new ArgumentNullException("name");
        }

        // Case-insensitive planet matching that lets exceptions fall through to caller
        return _planets[name.ToLower()];
    }
}

This implementation is not thread safe.

share|improve this answer
    
Why would you use a static planet manager? –  Stephen Mar 27 at 4:34
    
The way I see it, the static 'PlanetManager' offers the "easiest" access to 'Planet' information wherever it is needed without having to carry around an instance of it or worry about multiple 'Earth' instances being created. –  kcc Mar 27 at 18:38
1  
The problem that I have with making PlanetManager static is that there is state information that's stored in the dictionary. The list of planets is effectively unbounded and the user can add new ones at any time. It also makes the PlanetManager extremely difficult to test. If you want to avoid duplication, use a singleton pattern, but don't make the class static. –  Stephen Mar 27 at 23:25
    
My initial attempt with the PlanetManager as static. –  kcc Mar 28 at 22:17
    
I wasn't worried about the unbounded growth of the list because the way the items will really get used and the users. The testing argument wasn't really a big issue directly either for the way the overall system is developed and tested. I decided to try out the singleton version and was surprised to find out it actually offered a small performance gain. Maybe I'm naive but I was surprised by that. So I'm sticking with singletone. –  kcc Mar 28 at 22:20

You are, for whatever reason, hard-coding data into your program. This is itself a code smell (what do you do when mars suffers a catastrophic collision and losses 5% if it's mass?), but sometimes real code is smelly and there are some ways to do this which are better than others.

Since in our example we want to allow downstream programmers to create their own planet instances, we'll want a non-static Planet class or struct. And, since there are some real-life planets as well, some form of static method to populate that class would be appropriate. You could make a new sub-class for each standard planet, or you could make a distinct static method for each planet, but I think both patterns introduce too much complexity.

A simple single static 'static IPlanet GetPlanet(string name)' should suffice for interface's sake, and hard-coding the values wrapped inside some control structure is more than complexity enough. If an eight or nine branch method seems too complex for you, you can always go the clean route and just include an XML file with the data in your assembly.

Of course, if your "planets" really had different methods and internal behaviors, different classes would be appropriate.... but a single 'GetPlanet' method would still be a fair way to select between them.

share|improve this answer

Specifically, it seems like this exactly fits the flyweight pattern. Many of the answers have implemented this in various ways. Knowing the pattern name may help you research other possible approaches.

share|improve this answer

Similar to Stephen, but for a cleaner API, use an enum for the planets and inherit the PlanetManager from Dictionary. Like so:

public enum SolSystemPlanet { Earth }

public class PlanetManager : Dictionary<SolSystemPlanet, Planet>
{
    new public Planet this[SolSystemPlanet planet]
    {
        get 
        {
            if (!this.ContainsKey(planet))
                this.Add(planet, Create(planet));

            return base[planet];
        }
    }

    private static Planet Create(SolSystemPlanet planet)
    {
        switch (planet)
        {
            case SolSystemPlanet.Earth:
                return new Earth();
            default:
                throw new ArgumentException("Planet Not Supported");
        }
    }
}

The end result is that you get planets like so:

PlanetManager planets = new PlanetManager();
Console.WriteLine(planets[SolSystemPlanet.Earth].ToString());
share|improve this answer

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.