2

is it possible to structure functions inside a class, to make some functions only accessable through a prewritten identifier?

I'll try to make my question a litte more clear with a (poor) example ;-) My class car got the functions drive, openDoor, closeDoor, startEngine, etc. But, to keep it clear, i would like to acces these functions like this:

car.drive()
car.door.open()
car.door.close()
car.engine.start()

I tried with structs and nested classes, but i don't think those were the right ways, because i don't like to have to create an object for every "identifier" i use.

Are there any "clean" ways to do this?

Thanks!

Edit: I'm not sure if it matters but heres some additional information:

  • the "Car"-Class is Singelton
  • apart from the functions neither the engine nor the doors or any other part of my car do have any other properties (Yay. Really poor example!)
DIF
  • 2,470
  • 6
  • 35
  • 49

4 Answers4

3

Nested classes would be the correct approach.

Consider that all Door objects would have Open and Close methods, and a Car object would have several instances of the Door object (2, maybe 4, or even more).

Likewise, each Car object would have an instance of the Engine object, which can be Started, Stopped, and have the oil changed (ChangeOil).

Then, each of these classes would be extensible beyond the Car class. If you wanted to change some of the code inside of your Door class, all of your Car objects that have Doors would automatically inherit those changes. If you wanted to swap out the engine of a car with a more powerful one, you could do that easily by passing in a new instance of the Engine object to your Car object.

You could use structs the same way that you would use classes, but generally you should choose to use a class rather than a struct. Structs should be reserved for types that should have value type semantics, i.e., are small, immutable, etc. For more information on the difference and how to make an informed decision, see this question.

And just in case I failed to convince you that nested classes are the correct approach, I'll conclude by noting that they're also the only way of achieving what you want. That is, beyond hacky solutions like appending a pseudo-namespace to the beginning of each function name (i.e., Car.DoorOpen), which is ugly and doesn't really gain you anything at all.

Community
  • 1
  • 1
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Thanks for your answer! I just thought i should not use nested classes, because in this [answer](http://stackoverflow.com/a/8849079/1147455) it is said: _2) Do NOT use public nested types as a logical group construct_ But, considering nested classes again: I should use private nested classes and make an public object each, which holds the functions? – DIF Jan 13 '12 at 10:59
  • @user: Yes, the [Framework Design Guidelines](http://msdn.microsoft.com/en-us/library/ms229027.aspx) are telling you that what you're trying to do is generally a bad idea. They're right. But if you want to do it anyway (and they're just guidelines; they're not a rule), then this is how you do it. If it makes sense that the classes are private (i.e., that no external code should be able to create objects of that type), then make them private, yes. – Cody Gray - on strike Jan 13 '12 at 11:01
  • Thanks again! If this sort of grouping functions is considered a bad idea - how would the recommended way of organizing a lot of more or less different functions look like? – DIF Jan 13 '12 at 11:17
  • 1
    @Birgit_B: Well, I'm not sure why they need to be organized. Generally, people follow the single-responsibility-principle when designing classes. Classes should do one thing only. If your class starts doing more than one thing, you should break it up into multiple classes. If that one thing requires a lot of methods, well then it requires a lot of methods. Study the design of the .NET Framework classes—a lot of thought was put into them by some very smart people. There are some obvious gaffes and mistakes, but overall the design is pretty good. Some classes are quite complex, and that's okay. – Cody Gray - on strike Jan 13 '12 at 11:20
1

No - you would need to have a nested class door with its own methods. You could add your descriptor to the method name. So you would have

car.DoorOpen();
car.DoorClose();

I'd go for classes, since you may have properties that would apply more to the class door than to car. And add properties of the class door to car.

car.Door.Open();
Gambrinus
  • 2,140
  • 16
  • 26
1

Nested classes are not necessary here, for anyone having trouble understanding, the following is a nested class approach:

public class Car
{
    public static Car Instance { get; private set; }
    static Car() { Car.Instance = new Car(); }
    private Car() { }
    public static class Door
    {
        public static void Close()
        {
            /* do something with Car.Instance */
        } 
    }
}

The use of static classes yields the following syntax:

Car.Door.Close();

C# allows you to nest class definitions it does not have a formal concept of 'inner types' or 'inner classes' as other languages do.

This is an excellent example of poor component modeling/design.

Consider the following, which is a more acceptable and more elegant solution:

public interface ICar
{
    IDoor Door { get; set; } 
}

public class Car : ICar
{
    public IDoor Door { get; set; }
}

public interface IDoor
{
    void Open();
    void Close();
}

public class Door : IDoor
{
    public override void Open() { /* do something */ }
    public override void Close() { /* do something */ }
}

With the above could use C#'s initializer syntax:

var car = new Car
{
    Door = new Door()
};

car.Door.Open();

If your gripe is with constantly needing to type "new XYZ" you can also bake initialization into the constructor. Done properly with a 'poor man' DI pattern it should look like this:

public class Car : ICar
{
    public IDoor Door { get; set; }
    public Car()
        : this(new Door())
    {
    }
    public Car(IDoor door)
    {
        this.Door = door;
    }
}

This avoids the need to perform initialization as part of creation, and allows you to inject new/different Door types into the stack.

var common = new Car();
var lambo = new Car(new LamboDoor());

In either case, calling code looks the same:

common.Door.Open();
lambo.Door.Open();

Lastly, you could consider a Composition or DI framework rather than bake new() operators into your implementation code. In any case, the most appropriate approach is to use properties and construct a legitimate object model which expresses your intent. Nested types do not yield the syntax you're looking for unless static members are used and taking that approach is very rarely a good idea, I've only seen it for simplistic singleton implementations, certainly never for API/Framework/Model definition.

Shaun Wilson
  • 8,727
  • 3
  • 50
  • 48
0

Just my 2 sense.

I like @Code Gray idea of nested classes. But to achieve the correct order of calling the methods, I think you need to nest car under Driver. The Driver would do something like this.

public class Driver
{
   public void Drive(Car car)
   {
      car.drive();
      car.door.open();
      car.door.close();
      car.engine.start();
   }
}
Jesse Seger
  • 951
  • 1
  • 13
  • 31