Click here to Skip to main content
15,896,726 members
Please Sign up or sign in to vote.
1.00/5 (2 votes)
See more:
I hope my question is worded correctly. Please correct me if I am wrong.

I have a Class object called "Device". It contains several properties and methods. It also contains several other classes called Service1, Service2, and Service3. These classes also have several properties and methods.

My question is, what is the best practice to access the properties in the Device class from inside one of the ServiceX classes.

Here is my example

C#
public class Device
{
    public string Name { get; set; }
    public string IPAddress { get; set; }
    public string Port { get; set; }
    public Service1 service1 = new Service1();
    public Service2 service1 = new Service2();
    public Service3 service1 = new Service3();

}

public class Service1
{
    public string Identifier { get; set; }
    public string controlUrl { get; set; }

    public void executethis(string command)
    {
        string URL = @"http://" + Device.IPAddress + ":" + Device.Port + this.controlUrl
    }
}

public class Service2
{
    public string Identifier { get; set; }
    public string controlUrl { get; set; }

    public void executethis(string command)
    {
        string URL = @"http://" + Device.IPAddress + ":" + Device.Port + this.controlUrl
    }
}

public class Service3
{
    public string Identifier { get; set; }
    public string controlUrl { get; set; }

    public void executethis(string command)
    {
        string URL = @"http://" + Device.IPAddress + ":" + Device.Port + this.controlUrl
    }
}

So, if I use this is my application,
C++
Device.Service2.executethis("VolumeUp");

This or course does not work at all.

I have over come this by sending the parent object with it, like this:

C#
public class Device
{
    public string Name { get; set; }
    public string IPAddress { get; set; }
    public string Port { get; set; }
    public Service1 service1 = new Service1();
    public Service2 service1 = new Service2();
    public Service3 service1 = new Service3();

}

public class Service1
{
    public string Identifier { get; set; }
    public string controlUrl { get; set; }

    public void executethis(Device parent,string command)
    {
        string URL = @"http://" + parent.IPAddress + ":" + parent.Port + this.controlUrl
    }
}

public class Service2
{
    public string Identifier { get; set; }
    public string controlUrl { get; set; }

    public void executethis(Device parent,string command)
    {
        string URL = @"http://" + parent.IPAddress + ":" + parent.Port + this.controlUrl
    }
}

public class Service3
{
    public string Identifier { get; set; }
    public string controlUrl { get; set; }

    public void executethis(Device parent, string command)
    {
        string URL = @"http://" + parent.IPAddress + ":" + parent.Port + this.controlUrl
    }
}

now I use this:

C++
Device.Service2.executethis(Device, "VolumeUp");


But I'm sure this is not the correct way.
Posted

First of all, all our consideration only applicable to the trees of objects, not to arbitrary object graphs.

I don't see a specific problem. If you navigate from children up to the parent more or less frequently, the "best practice" would be having Parent references in all nodes of the tree, without exclusion.

One big potential problem is polymorphism, and hence the question: what type should be the type of Parent? It is possible that some child node can be composed in two or more difference parent types. Breaking OOP with dynamic cast (down-casting) is a kind of nasty thing. But in your case, you have only one Device type. So, there is really nothing to discuss here.

—SA
 
Share this answer
 
Comments
Sascha Lefèvre 27-May-15 19:10pm    
+5. I expanded on your second paragraph a bit.
/Sascha
Sergey Alexandrovich Kryukov 27-May-15 23:12pm    
Thank you, Sascha.
—SA
HKHerron 28-May-15 8:54am    
Thank you Sergey Alexandrovich Kryukov for your explanation and response. +5
I am selecting Solution 2 as the accepted answer as it expands on your thoughts, while providing the best explanations, alternatives and options.
Sergey Alexandrovich Kryukov 28-May-15 9:59am    
You are very welcome. By the way, you don't have to "select" a solution to accept; you can accept any subset of solutions, accept any number of them; you decide, of course.
Good luck, call again.
—SA
In addition to solution 1:

You could:

1) Introduce a field "Parent" in your Service-classes; of type Device (or, bearing Sergey's comment on polymorphism in mind, maybe rather an interface that Device implements).

2) Don't initialize the fields for the Service-instances in Device in the class-body but instead in the constructor.

3) Introduce an argument to the constructors of the service-classes; of type Device (or that interface) and provide it in form of the this-keyword in the constructor of Device when initializing the fields for the Service-instances.

If you can't follow me here, please ask.

Unrelated suggestions:
- Avoid public setters (for properties), here: Name, IPAddress, Port. Make them protected or private.
- Change the fields for the Service-instances in Device to properties (again, with non-public setters).
- Use C# naming rules: PascalCasing (starting with a capital) for all class members: Fields, Properties, Methods. camelCasing only for local identifiers.


edit: Picking up on Dave's answer, I think it could make sense to change your design a bit. Because this:
C#
Device.Service2.executethis("VolumeUp");

..looks a bit fishy. Essentially it's the Service here that you're using, not the Device. And the Service is using the Device. But why is the Service then a member of Device? If you flipped this around, making Device a member of Service, it would look like this:
C#
Device device1 = new Device(name, ipaddress, port);
Service2 service2 = new Service2(device1);
service2.executethis("VolumeUp");

..and you wouldn't have to access a parent's members from its child objects.
 
Share this answer
 
v3
Comments
Sergey Alexandrovich Kryukov 27-May-15 23:11pm    
Makes sense, a 5.
—SA
Sascha Lefèvre 28-May-15 15:02pm    
Thank you, Sergey.
HKHerron 28-May-15 9:06am    
1st, Thank you Sascha for your explanations and examples.
This makes the most sense to me.

Not sure if this would matter, but I should explain that there may be (say) 6 different Device objects. But they all use Service1, Service2 and Service3.
The Device objects are found through a UPnP broadcast that returns a list containing the url to each devices description.xml file. Each Device object is then populated according to the information found in the description file. This is where the services are found for that device.

Since all my devices use the same services, maybe I should just consider NOT making the Services even part of the Device object at all, but stand alone classes.

Then I could use something like: Service2.executethis(Device, "VolumeUp");
Sascha Lefèvre 28-May-15 15:01pm    
You're welcome!
Yes, I think that would make the most sense in that case. Good luck! :)
/Sascha
Best practice is YOU DON'T!

The child object should not care about it's parents data AT ALL. The scope the child object should be concerned with is it's own data and that's it. Nothing else.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 27-May-15 23:16pm    
Sorry my friend, really sorry. This is what I call dogmatism, and this is what I think is bad.
The access to the parent is the decision which may depend on a number of different factors. Basically, you have some graph, a tree or not, need to travel on it using different algorithms and on different purposes. Consider all these operations, performance and memory costs, and then decide what to reference from what and what not.
I cannot believe I down-vote you answer; probably it happened for the fist time. Hope you can understand my frustration. Really sorry.
—SA
Dave Kreskowiak 27-May-15 23:43pm    
I understand. I was taught the a child never should know anything concrete about it's parent. Sure, it can have a reference to it, for example, linked lists or trees, but the child should never give a crap about it's parents data.

I've been writing code with that in mind for quite a long time and have never violated the 'rule'. :)
Sergey Alexandrovich Kryukov 28-May-15 0:43am    
What you have been taught does not have to be true in all cases.

Just few examples (which of course don't prove anything, just illustrations). 1) Whole relational model is based on the idea that only the child knows about parent, and parent does not know about children, just because a table has fixed number of columns; there is the attribute "parent"; and this is how integral picture is assembled; 2) System.Windows.Forms.Control.Parent.
How come they violated the "rule"? This is false rule, I tell you. Sorry.

But maybe three of us did not simply understand each other. The reference to the parent is the way "the child objects cares about parent's data". If you did not mind this reference, you simply expressed yourself in a misleading way. Do you think that anyone has such a crazy idea that the parent has, say, property "A", and all the children may have copies of the attribute "A", which are yet to be synchronized, and so on. I could not imagine that anyone in sober mind could ever come to such idea. This would be the most idiotic way of violating Single-Point-Of-Truth (SPOT) principle, which is of course purely rational and not dogmatic at at all, should not be violated (don't mix it up with redundancy which can be very useful).

This is not so simple. Let's again look at the relational model. What is "parent" in the children table? It is represented by the foreign key pointing to one or another parent. But in the parents table, this corresponds to some attribute, such as "id". So, in this sense, this attribute as a foreign key is "copied" in the children. But this is logically equivalent to a reference: a child has a reference to the parent. And not visa versa.

—SA
Dave Kreskowiak 28-May-15 12:19pm    
Well, it looks like I lied a little bit. I did use the pattern when I wrote 'Runtime movable controls'. The control needs the parent container for some stuff. :) Opps.

Really, under OOP, should a child know anything about the data structures of its parent? I'm not saying it isn't useful at times. I'm just asking if it is really "best practice" for a child to care? I'm my humble opinion, no.

Sergey Alexandrovich Kryukov 28-May-15 12:38pm    
It is a good practice (through references, of course), in some cases, and never having references to parents is a good practice for other cases. It all depends, first of all, on required set of operations, the ways you have to navigate.

And having those references is by far more typical than not having them. I would say, overwhelmingly more typical. I already gave you two examples. Here are two more:
XML DOM, XMLNode: https://msdn.microsoft.com/en-us/library/system.xml.xmlnode.parentnode%28v=vs.110%29.aspx
JavaScript DOM interface: https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement.

And those 4 (yes, 4 now) examples of tree representations are themselves some of the most used objects in programming. Again, it does not prove anything, but is very illustrative.

—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900