Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hiding implementational detail from parent classes

Tags:

c#

oop

Suppose I'm designing a robot that can pickup various tools and use them. I would create a Robot class which has Pickup method to pick the tools I wanted to use. For each tools I would create a class for it, say, Knife class which has Cut method. After invoking a Pickup method on Robot now I want to tell my robot to cut. So for OOP concept I have to tell the robot, not knife? And the Cut method is on Knife so how can I invoke that? I have to implement some kind of UseToolCurrentlyHeld() on Robot to propagate my commands to Knife. Or I just directly call the knife (that my robot hold) directly using this: myrobot.ToolCurrentlyInHand.Cut()

I feel it's weird that a parent method must have EVERYTHING to take care of classes they contain. Now I have duplicate methods, like the Knife has Cut() and now Robot must have UseCutOnKnife() only to invoke Cut() on Knife because good OOP practice is to abstract the Knife out and make it feel like ordering a Robot without worrying about internal information like Knife.

Another question, if I composing a music I would create Music class which contains many Measure class to store note information. In one Measure there can be many Note class inside it which Note class will have information like, where in the measure does this note reside, or how long that note plays. Now I want to add one note on measure 45 placed on about middle of the measure. To create the Measure I have to call CreateMeasure(45) on Music and then call CreateNote(0.5f) on Measure? The method to create is on the parent like that? And if now I want to change that note to be at 0.25 on the measure instead, the one responsible to have method to change Note is the Note class itself or Measure class? Or I must implement the method to change notes on the topmost Music class?

This is overview of my classes :

class Music
{
     List<Measure> measures = new List<Measure>();

     //methods...
}

class Measure
{
     int measureNumber;
     List<Note> notes = new List<Note>();

     //methods...
}

class Note
{
     float positionInMeasure; //from 0 to 1
}

As now the Music class is on top of everything I now have to issue everything through Music? And chaining the method to finally call the innermost class?

like image 209
5argon Avatar asked Dec 20 '22 20:12

5argon


2 Answers

What you need here is a common interface that all the tools implement.

E.g.:

interface ITool {
    void Use();
}

Now the knife can implement that interface:

class Knife : ITool {
    public void Use() {
        //do the cutting logic
    }
}

Now you would use the tool through the ITool interface on the robot, not knowing what tool it is:

class Robot {
    private ITool currentTool = null;

    public void Pickup(ITool tool)
    {
        currentTool = tool;
    }

    public void UseTool() {
        currentTool.Use();
    }
} 

And you can invoke Pickup like that:

 Robot robot = new Robot();
 robot.Pickup(new Knife());
 robot.UseTool();
like image 190
Petar Ivanov Avatar answered Dec 23 '22 10:12

Petar Ivanov


I instead suggest a different approach. Have Knife and all other objects the robot can pick inherit from a generic class Item with a method Use (can also be an interface):

interface Item
{
    void Use();
}

class Knife : Item
{
    public void Use()
    {
        // cut action
    }
}

Now each class implementing Item will have its own implementation of the Use method for its specific action.

Then the Robot holds a generic Item and calls Use on it without knowing what it actually is:

class Robot
{
     public Item CurrentItem { get; private set; }

     public void PickUpItem(Item i)
     {
         CurrentItem = i;
     }

     public void UseItem()
     {
         CurrentItem.Use(); // will call Use generically on whatever item you're holding
     }         
}

...

Robot r = new Robot();
r.PickUpItem(new Knife());
r.UseItem(); // uses knife

r.PickUpItem(new Hammer());
r.UseItem(); // uses hammer
like image 31
Tudor Avatar answered Dec 23 '22 10:12

Tudor