Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

Class design

Options
  • 20-11-2012 8:53am
    #1
    Registered Users Posts: 1,466 ✭✭✭


    Hi All,

    I have a class design issue that is bugging me.

    I was playing around with a game simlar to tetris.

    I have a base class called block and two derived class. One callled standardblock and another called powerblock. At the moment the derived classes only vary from the base class by having different blockstyles (standard blocks have colours while powerblocks have styles like large explosion etc)

    Scattered all through the code is lines like :

    if block is a standardblock
    -- do standard action
    else
    -- do power action

    Is there a design pattern or some obvious class adjustment that would tidy up this code ?

    Thanks


Comments

  • Moderators, Technology & Internet Moderators Posts: 1,334 Mod ✭✭✭✭croo


    Look at polymorphism.


  • Registered Users Posts: 4,443 ✭✭✭robbiezero


    Smoggy wrote: »
    Hi All,

    I have a class design issue that is bugging me.

    I was playing around with a game simlar to tetris.

    I have a base class called block and two derived class. One callled standardblock and another called powerblock. At the moment the derived classes only vary from the base class by having different blockstyles (standard blocks have colours while powerblocks have styles like large explosion etc)

    Scattered all through the code is lines like :

    if block is a standardblock
    -- do standard action
    else
    -- do power action

    Is there a design pattern or some obvious class adjustment that would tidy up this code ?

    Thanks

    Yes.
    block.doAction().


  • Registered Users Posts: 11 SionnachRoe


    Explicit checks on type and performing different actions based upon the type is a well known 'code smell' (e.g. http://hanuska.blogspot.ie/2006/08/swich-statement-code-smell-and.html) and should be avoided.

    A solution is

    1) Decide upon all the functionality that you expect all of your classes to execute and then define an interface
        public interface IBlock {
            void rotate();
            void moveDown();
            void doXXX();
        }
    

    This is our contract. It tells the rest of the system what functionality can be expected from all blocks.

    2) Create a base class which implements the interface and contains all the common functionality. Make all the interface methods virtual
        public class Block : IBlock {
            public virtual void rotate() {
                  //default implementation
            }
            public virtual void moveDown() {
                  //default implementation
            }
            public virtual void doXXX() {
                  //default implementation
            }
        }
    

    3) Create derived classes for the specific functionality (in this case the Power block)
        public class PowerBlock : Block {
             public override void doXXX(){
                 // specific functionality
        } 
    


    4) If we have a collection of blocks we use the IBlock type (e.g. List<IBlock>) and simply iterate through the objects
        ...
     
        List<IBlock> blocks = getBlocks();
     
        for(IBlock block: blocks){
             block.doXXX();
        }
     
        ...
     
    


    Notes:

    Why the interface?

    It is not totally required but prevents leakage around the edges of the abstraction. If we are developing against the contract (interface) rather than concrete classes it gives us a better feeling for how tight the abstraction is.
    - If we find ourselves adding functionality to the interface which is used only in one concrete class then we are doing something wrong.
    - If we find ourselves casting to concrete types and calling members which are not in the interface then we are doing something wrong.

    An interface is also very useful for unit testing (creating mock objects/stubs).


  • Registered Users Posts: 3,945 ✭✭✭Anima


    Good advice SionnachRoe but isn't that C#?

    #Edit: Actually he didn't specify a language :|. virtual isn't in Java just to be clear!


  • Registered Users Posts: 11 SionnachRoe


    Anima wrote: »
    Good advice SionnachRoe but isn't that C#?

    #Edit: Actually he didn't specify a language :|. virtual isn't in Java just to be clear!

    Yep, my bad.
    I was doing it quickly and lapsed into C#. Everything, except for the virtual keyword should work in java (one can use @Override in java but afaik simply using the same signature is sufficient to override in java)


  • Advertisement
  • Registered Users Posts: 2,021 ✭✭✭ChRoMe


    Yep, my bad.
    I was doing it quickly and lapsed into C#. Everything, except for the virtual keyword should work in java (one can use @Override in java but afaik simply using the same signature is sufficient to override in java)

    Any decent IDE should at least warn over not using @Override, its bad practice.


  • Registered Users Posts: 1,466 ✭✭✭Smoggy


    Thanks SionnachRoe ! I knew it stunk but I didn't know why :)

    I will do some refactoring and come back with the results.


  • Registered Users Posts: 4,443 ✭✭✭robbiezero


    ChRoMe wrote: »
    Any decent IDE should at least warn over not using @Override, its bad practice.

    Yes it is.
    I have Eclipse set to warn on missing Overrides and to add them automatically on save.


  • Registered Users Posts: 27,161 ✭✭✭✭GreeBo


    robbiezero wrote: »
    Yes it is.
    I have Eclipse set to warn on missing Overrides and to add them automatically on save.

    Note that you cannot use @Override against an interface until java 1.6 and beyond. jdk1.5 will moan and complain about it.


Advertisement