Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. Design and Architecture
  4. Simple composition - Your thoughts?

Simple composition - Your thoughts?

Scheduled Pinned Locked Moved Design and Architecture
questiontutorialdiscussion
17 Posts 5 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • E Eytukan

    What is your way of dealing with a composition in a class? Will you force the user to pass the required values to the contained objects? Or you'll let the user set the contained object anytime later and check for it's validity everywhere? For example,

    class Rocket
    {
    Booster b1;
    Rocket(Boostertype bt, BoosterPower bp)
    {
    //check bp & bt values for acceptable range else throw an exception
    b1 = new Booster(bt,bp);
    }
    Launch()
    {
    b1.fire();
    //We are sure Booster is initialized
    }
    }

    Or it could be done this way

    class Rocket
    {
    Booster b1;
    Rocket()
    {

    }
    initBooster(Boostertype bt, BoosterPower bp)
    {

    b1 = new Booster(bt,bp);
    

    }
    Launch()
    {
    if(null!=b1)
    {
    if(b1.bp >100)
    {
    //Ok to launch
    }
    }
    // booster may not be initialized yet. so check and throw an exception if not inited.
    }
    }

    My preferred way is to enforce Rocket's constructor with params required for booster as well. Unless we pass a sensible value for the booster, rocket creation will fail. But my mate here seem to differ with my opinion. He doesn't want Rocket's creation to be disturbed by booster constructors parameters. Instead, when a Launch() is called , it should throw an exception saying Booster is not initialized/configured. Which one would you prefer?

    Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.

    B Offline
    B Offline
    BobJanova
    wrote on last edited by
    #5

    As Pete says, a constructor should always return a valid object, that is, you should be able to use it in normal situations. So the answer to the question depends on whether a Rocket can be useful without a Booster. In your simplistic example, where it has one method and that method throws an exception if it isn't set, it clearly can't, and therefore the Booster should be assigned in the constructor (and, if applicable, a null check applied there).

    1 Reply Last reply
    0
    • P Pete OHanlon

      It's an interesting one to say the least. One of the principals of OO development is that you shouldn't return an object out of a constructor that requires further configuration to be useful*. In other words, you shouldn't need to set additional properties before the class is useful. In this particular case, the fact that you can get to the Launch code without setting it, and the first point that you notice that there's a failure is at this point would indicate that the Booster should have been applied earlier on. *Now, looking at your sample, it would seem that what you are looking at here is an object that would typically be composed using Dependency Injection, so it would be reasonable to assume that the DI code would actually compose your object for you. This would mean that you would be exposing a dependency that your code was reliant on - and this is where it gets slightly murkier. If you favour the wide constructor approach to composition, then every time you need to add an extra dependency to your class, you have to add it to your constructor, and add a backing field for that type. You may prefer the dependency property (I'm not using this in the WPF way here) approach, which means that you would expose a property for it - and this could be an auto property so you wouldn't need to add the field yourself as the compiler takes care of this for you behind the scenes.

      *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

      "Mind bleach! Send me mind bleach!" - Nagy Vilmos

      CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

      N Offline
      N Offline
      Nagy Vilmos
      wrote on last edited by
      #6

      Using the analogy of the rocket, you can still perform a lot of actions - giro tests, etc - without a booster. The booster is an added item, not necessarily an intrinsic part. If the rocket must have a booster, then I agree it must be a part of the constructor to ensure its presence.


      Panic, Chaos, Destruction. My work here is done. Drink. Get drunk. Fall over - P O'H OK, I will win to day or my name isn't Ethel Crudacre! - DD Ethel Crudacre I cannot live by bread alone. Bacon and ketchup are needed as well. - Trollslayer Have a bit more patience with newbies. Of course some of them act dumb - they're often *students*, for heaven's sake - Terry Pratchett

      P 1 Reply Last reply
      0
      • E Eytukan

        What is your way of dealing with a composition in a class? Will you force the user to pass the required values to the contained objects? Or you'll let the user set the contained object anytime later and check for it's validity everywhere? For example,

        class Rocket
        {
        Booster b1;
        Rocket(Boostertype bt, BoosterPower bp)
        {
        //check bp & bt values for acceptable range else throw an exception
        b1 = new Booster(bt,bp);
        }
        Launch()
        {
        b1.fire();
        //We are sure Booster is initialized
        }
        }

        Or it could be done this way

        class Rocket
        {
        Booster b1;
        Rocket()
        {

        }
        initBooster(Boostertype bt, BoosterPower bp)
        {

        b1 = new Booster(bt,bp);
        

        }
        Launch()
        {
        if(null!=b1)
        {
        if(b1.bp >100)
        {
        //Ok to launch
        }
        }
        // booster may not be initialized yet. so check and throw an exception if not inited.
        }
        }

        My preferred way is to enforce Rocket's constructor with params required for booster as well. Unless we pass a sensible value for the booster, rocket creation will fail. But my mate here seem to differ with my opinion. He doesn't want Rocket's creation to be disturbed by booster constructors parameters. Instead, when a Launch() is called , it should throw an exception saying Booster is not initialized/configured. Which one would you prefer?

        Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.

        M Offline
        M Offline
        Marc Clifton
        wrote on last edited by
        #7

        Neither. Rocket should be able to call a factory method "Boosters.GetBooster()", or some other suitable mechanism to acquire what it needs, when it needs it. Marc

        My Blog
        The Relationship Oriented Programming IDE
        Melody's Amazon Herb Site

        P E 2 Replies Last reply
        0
        • N Nagy Vilmos

          Using the analogy of the rocket, you can still perform a lot of actions - giro tests, etc - without a booster. The booster is an added item, not necessarily an intrinsic part. If the rocket must have a booster, then I agree it must be a part of the constructor to ensure its presence.


          Panic, Chaos, Destruction. My work here is done. Drink. Get drunk. Fall over - P O'H OK, I will win to day or my name isn't Ethel Crudacre! - DD Ethel Crudacre I cannot live by bread alone. Bacon and ketchup are needed as well. - Trollslayer Have a bit more patience with newbies. Of course some of them act dumb - they're often *students*, for heaven's sake - Terry Pratchett

          P Offline
          P Offline
          Pete OHanlon
          wrote on last edited by
          #8

          Nagy Vilmos wrote:

          If the rocket must have a booster, then I agree it must be a part of the constructor to ensure its presence.

          And that's the rub. What constitues a valid instance of the class? In the admittedly contrived example given, the only operation that could be performed was a Launch, so the booster is an intrinsic part of this particular example. Now, if this class were one I was designing, I would take a slightly different approach if this was a full lifecycle of a rocket. This particular rocket implementation is tightly coupled to a single booster. What happens if I want a rocket with more than one booster? Or I want to use one that's based on the ACME Fusion Drive 3000 elastic band? To that end, I'd consider that a design like this might be better:

          public class Rocket
          {
          public Rocket()
          {
          }

          public void PreLaunchTests()
          {
          OnPreLaunchTests();
          }

          public void Launch()
          {
          }

          protected virtual void OnPreLaunchTests()
          {
          }

          protected virtual void OnLaunch()
          {
          }
          }

          public class SingleBoosterRocket : Rocket
          {
          public List<IBooster> Boosters { get; private set; }

          public SingleBoosterRocket()
          {
          Boosters = new List<IBooster>();
          }

          public void AddBooster(IBooster booster)
          {
          Boosters.Add(booster);
          }

          protected override void OnPreLaunchTests()
          {
          // Do some pre launch tests.
          }

          protected override void OnLaunch()
          {
          if (Boosters.Count == 0)
          throw new NotEnoughBoostersException();
          // Do some other work.
          }
          }

          public class DualBoosterRocket : SingleBoosterRocket
          {

          public DualBoosterRocket() : base()
          {
          }

          protected override void OnPreLaunchTests()
          {
          // Do some pre launch tests.
          }

          protected override void OnLaunch()
          {
          if (Boosters.Count < 2)
          throw new NotEnoughBoostersException();
          // Do some other work.
          }
          }

          Again, this is a completely fabricated design, but this has the advantage of being more flexible. Ultimately, the design should be based on the real requirements, which is why I have steered well clear of saying that one approach is better than another in all cases. BTW - in case you're wondering, the actual composition in this sample has been moved to the containing object, rather than the actual rocket implementation, as that piece of code would be the one that decided what the composition entailed. The rules for the rocket have been

          E 1 Reply Last reply
          0
          • M Marc Clifton

            Neither. Rocket should be able to call a factory method "Boosters.GetBooster()", or some other suitable mechanism to acquire what it needs, when it needs it. Marc

            My Blog
            The Relationship Oriented Programming IDE
            Melody's Amazon Herb Site

            P Offline
            P Offline
            Pete OHanlon
            wrote on last edited by
            #9

            Funnily enough, that was the gist of the answer that I've just added above.

            *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

            "Mind bleach! Send me mind bleach!" - Nagy Vilmos

            CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

            M 1 Reply Last reply
            0
            • P Pete OHanlon

              Funnily enough, that was the gist of the answer that I've just added above.

              *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

              "Mind bleach! Send me mind bleach!" - Nagy Vilmos

              CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

              M Offline
              M Offline
              Marc Clifton
              wrote on last edited by
              #10

              Pete O'Hanlon wrote:

              Funnily enough, that was the gist of the answer that I've just added above.

              I read it, but your response was too wordy for me to figure out what you were saying! But none-the-less, two great minds, a single thought between them, eh? Dependency Injection, hmmm... it's really weird to me how we have these (what I consider to be) massive frameworks to support DI when all it really needs is a simple instantiation engine. Anyways, I'm getting distracted by the lure of an unoccupied soapbox. ;) Marc

              My Blog
              The Relationship Oriented Programming IDE
              Melody's Amazon Herb Site

              P 1 Reply Last reply
              0
              • M Marc Clifton

                Pete O'Hanlon wrote:

                Funnily enough, that was the gist of the answer that I've just added above.

                I read it, but your response was too wordy for me to figure out what you were saying! But none-the-less, two great minds, a single thought between them, eh? Dependency Injection, hmmm... it's really weird to me how we have these (what I consider to be) massive frameworks to support DI when all it really needs is a simple instantiation engine. Anyways, I'm getting distracted by the lure of an unoccupied soapbox. ;) Marc

                My Blog
                The Relationship Oriented Programming IDE
                Melody's Amazon Herb Site

                P Offline
                P Offline
                Pete OHanlon
                wrote on last edited by
                #11

                We internally have a DI engine that is only 60 lines or so of code, and it's good enough for our purposes when all we need is basic DI.

                *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

                "Mind bleach! Send me mind bleach!" - Nagy Vilmos

                CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

                M 1 Reply Last reply
                0
                • P Pete OHanlon

                  Nagy Vilmos wrote:

                  If the rocket must have a booster, then I agree it must be a part of the constructor to ensure its presence.

                  And that's the rub. What constitues a valid instance of the class? In the admittedly contrived example given, the only operation that could be performed was a Launch, so the booster is an intrinsic part of this particular example. Now, if this class were one I was designing, I would take a slightly different approach if this was a full lifecycle of a rocket. This particular rocket implementation is tightly coupled to a single booster. What happens if I want a rocket with more than one booster? Or I want to use one that's based on the ACME Fusion Drive 3000 elastic band? To that end, I'd consider that a design like this might be better:

                  public class Rocket
                  {
                  public Rocket()
                  {
                  }

                  public void PreLaunchTests()
                  {
                  OnPreLaunchTests();
                  }

                  public void Launch()
                  {
                  }

                  protected virtual void OnPreLaunchTests()
                  {
                  }

                  protected virtual void OnLaunch()
                  {
                  }
                  }

                  public class SingleBoosterRocket : Rocket
                  {
                  public List<IBooster> Boosters { get; private set; }

                  public SingleBoosterRocket()
                  {
                  Boosters = new List<IBooster>();
                  }

                  public void AddBooster(IBooster booster)
                  {
                  Boosters.Add(booster);
                  }

                  protected override void OnPreLaunchTests()
                  {
                  // Do some pre launch tests.
                  }

                  protected override void OnLaunch()
                  {
                  if (Boosters.Count == 0)
                  throw new NotEnoughBoostersException();
                  // Do some other work.
                  }
                  }

                  public class DualBoosterRocket : SingleBoosterRocket
                  {

                  public DualBoosterRocket() : base()
                  {
                  }

                  protected override void OnPreLaunchTests()
                  {
                  // Do some pre launch tests.
                  }

                  protected override void OnLaunch()
                  {
                  if (Boosters.Count < 2)
                  throw new NotEnoughBoostersException();
                  // Do some other work.
                  }
                  }

                  Again, this is a completely fabricated design, but this has the advantage of being more flexible. Ultimately, the design should be based on the real requirements, which is why I have steered well clear of saying that one approach is better than another in all cases. BTW - in case you're wondering, the actual composition in this sample has been moved to the containing object, rather than the actual rocket implementation, as that piece of code would be the one that decided what the composition entailed. The rules for the rocket have been

                  E Offline
                  E Offline
                  Eytukan
                  wrote on last edited by
                  #12

                  Thanks for the example Pete :)

                  Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.

                  P 1 Reply Last reply
                  0
                  • M Marc Clifton

                    Neither. Rocket should be able to call a factory method "Boosters.GetBooster()", or some other suitable mechanism to acquire what it needs, when it needs it. Marc

                    My Blog
                    The Relationship Oriented Programming IDE
                    Melody's Amazon Herb Site

                    E Offline
                    E Offline
                    Eytukan
                    wrote on last edited by
                    #13

                    I think we can think about two scenarios: 1. First, On the ground, we "build" the rocket with boosters and make a launch. 2. We don't build or assemble a rocket, but when a launch is called, it acquires a booster and executes a launch. The second one is loosely tied. The Boosters.GetBooster() can be applied for both the scenarios?

                    Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.

                    M 1 Reply Last reply
                    0
                    • E Eytukan

                      Thanks for the example Pete :)

                      Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.

                      P Offline
                      P Offline
                      Pete OHanlon
                      wrote on last edited by
                      #14

                      Not a problem.

                      *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

                      "Mind bleach! Send me mind bleach!" - Nagy Vilmos

                      CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

                      1 Reply Last reply
                      0
                      • P Pete OHanlon

                        We internally have a DI engine that is only 60 lines or so of code, and it's good enough for our purposes when all we need is basic DI.

                        *pre-emptive celebratory nipple tassle jiggle* - Sean Ewington

                        "Mind bleach! Send me mind bleach!" - Nagy Vilmos

                        CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier

                        M Offline
                        M Offline
                        Marc Clifton
                        wrote on last edited by
                        #15

                        Pete O'Hanlon wrote:

                        We internally have a DI engine that is only 60 lines or so of code

                        Sweet! Marc

                        My Blog
                        The Relationship Oriented Programming IDE
                        Melody's Amazon Herb Site

                        1 Reply Last reply
                        0
                        • E Eytukan

                          I think we can think about two scenarios: 1. First, On the ground, we "build" the rocket with boosters and make a launch. 2. We don't build or assemble a rocket, but when a launch is called, it acquires a booster and executes a launch. The second one is loosely tied. The Boosters.GetBooster() can be applied for both the scenarios?

                          Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.

                          M Offline
                          M Offline
                          Marc Clifton
                          wrote on last edited by
                          #16

                          VuNic wrote:

                          The Boosters.GetBooster() can be applied for both the scenarios?

                          I think so. In the first scenario, the constructor can call GetBooster to get a concrete instance, though I think it would be much more preferable for Rocket to have a Build() method. In the second scenario, and this may be over the top, consider that we know that a rocket, among other things, has some form of propulsion mechanism, otherwise it wouldn't be a rocket. Now, a rocket might have a main engine, boosters, stages, ion engines, so forth, a whole slew of combinations of things. So if rocket is to have a "has a" relationship to booster, the concept of booster needs to be abstracted to "propulsion systems", ideally a collection of this abstraction type. The GetBooster factory might return a collection specific to the rocket's requirements. You can define specific collections as a concrete type (there's most likely a limited, well defined set of configurations). Each type (the configuration of propulsion systems) probably has specific launch behaviors. Therefore, the type itself contains all the logic for how to proceed with a launch, going from main engine firing, booster firing, stages, and final orbit maneuverings with ion engines. So, why should the rocket itself know how to do this? The rocket is just a container for a particular configuration. Maybe the rocket performs some coordination with other systems, but the execution of the launch should be delegated to the configuration type. Which is where functional programming can be used, not only for "computing" the launch, but also for ensuring that configurations, using discriminated unions, are permitted. :) Marc

                          My Blog
                          The Relationship Oriented Programming IDE
                          Melody's Amazon Herb Site

                          E 1 Reply Last reply
                          0
                          • M Marc Clifton

                            VuNic wrote:

                            The Boosters.GetBooster() can be applied for both the scenarios?

                            I think so. In the first scenario, the constructor can call GetBooster to get a concrete instance, though I think it would be much more preferable for Rocket to have a Build() method. In the second scenario, and this may be over the top, consider that we know that a rocket, among other things, has some form of propulsion mechanism, otherwise it wouldn't be a rocket. Now, a rocket might have a main engine, boosters, stages, ion engines, so forth, a whole slew of combinations of things. So if rocket is to have a "has a" relationship to booster, the concept of booster needs to be abstracted to "propulsion systems", ideally a collection of this abstraction type. The GetBooster factory might return a collection specific to the rocket's requirements. You can define specific collections as a concrete type (there's most likely a limited, well defined set of configurations). Each type (the configuration of propulsion systems) probably has specific launch behaviors. Therefore, the type itself contains all the logic for how to proceed with a launch, going from main engine firing, booster firing, stages, and final orbit maneuverings with ion engines. So, why should the rocket itself know how to do this? The rocket is just a container for a particular configuration. Maybe the rocket performs some coordination with other systems, but the execution of the launch should be delegated to the configuration type. Which is where functional programming can be used, not only for "computing" the launch, but also for ensuring that configurations, using discriminated unions, are permitted. :) Marc

                            My Blog
                            The Relationship Oriented Programming IDE
                            Melody's Amazon Herb Site

                            E Offline
                            E Offline
                            Eytukan
                            wrote on last edited by
                            #17

                            Hmm as I understand, the design decision completely relies on the exact requirement. More thinking is required to realize what is the system about. The more we are precise with the actual system, the better and sensible design we could make. Thanks for the inputs Marc. All learning for me :)

                            Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.

                            1 Reply Last reply
                            0
                            Reply
                            • Reply as topic
                            Log in to reply
                            • Oldest to Newest
                            • Newest to Oldest
                            • Most Votes


                            • Login

                            • Don't have an account? Register

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • World
                            • Users
                            • Groups