61

In my program design, I often come to the point where I have to pass object instances through several classes. For example, if I have a controller that loads an audio file, and then passes it to a player, and the player passes it to the playerRunnable, which passes it again somewhere else etc. It looks kind of bad, but I don´t know how to avoid it. Or is it OK to do this?

EDIT: Maybe the player example is not the best because I could load the file later, but in other cases that does not work.

12 Answers 12

55

As others have mentioned, this isn't necessarily a bad practice, but you should pay attention that you're not breaking the layers' separation of concerns and passing layer-specific instances between layers. For instance:

  • Database objects should never be passed up to higher layers. I've seen programs using .NET's DataAdapter class, a DB-access class, and passing it up to the UI layer, rather than using the DataAdapter in the DAL, creating a DTO or dataset, and passing that up. DB access is the domain of the DAL.
  • UI objects should, of course, be limited to the UI layer. Again, I've seen this violated, both with ListBoxes populated with user data passed up to the BL layer, instead of an array/DTO of its content, and (a particular favorite of mine), a DAL class that retrieved hierarchical data from the DB, and rather than returning a hierarchical data structure, it just created and populated a TreeView object, and passed it back to the UI to be added dynamically to a form.

However, if the instances you're passing are the DTOs or entities themselves, it's probably ok.

7
  • 1
    This might sound shocking, but in the dark early days of .NET that was the generally recommended practice and was probably better than what most other stacks are doing. Sep 27, 2012 at 13:38
  • 1
    I disagree. It's true that Microsoft endorsed the practice of single-layer apps where the Winforms client also accessed the DB, and the DataAdapter was added directly to the form as an invisible control, but that's just a specific architecture, different from the OP's N-tier setup. But in a multilayer architecture, and this was true for VB6/DNA even before .NET, DB objects stayed in the DB layer. Sep 27, 2012 at 13:41
  • To clarify: you've seen people accessing the UI directly (in your example, listboxes) from their "Data Layer"? I don't think I've come across such a violation in production code.. wow.. Sep 27, 2012 at 13:43
  • 8
    @SimonWhitehead Exactly. People who were fuzzy about the distinction betwen a ListBox and an array, and used ListBoxes as a DTO. It was a moment that helped me realize how many invisible assumptions I make that aren't intuitive to others. Sep 27, 2012 at 13:54
  • 1
    @SimonWhitehead - Yes, aadly I've seen that in VB6 and VB.NET Framework 1.1 and 2.0 programs and have been tasked to maintain such monsters. It gets very ugly, very quickly.
    – jfrankcarr
    Sep 27, 2012 at 15:05
15

Interesting that no one has talked about Immutable objects yet. I would argue that passing an immutable object around through all the various layers is actually a good thing rather than creating lots of short lived objects for each layer.

There are some great discussions of immutability by Eric Lippert on his blog

On the other hand I'd argue that passing mutable objects between layers is bad design. You're essentially building a layer with the promise that surrounding layers won't alter it in a way to break your code.

0
13

Passing object instances around is a normal thing to do. It reduces the need for keeping the state (i.e. instance variables) and decouples the code from its execution context.

One issue that you may face is refactoring, when you must change signatures of multiple methods along the invocation chain in response to changing parameter requirements of a method near the bottom of that chain. However, it can be mitigated with the use of modern software development tools that help in refactoring.

1
  • 6
    I'd say another issue you may face involves immutability. I can remember a very perplexing bug in a project I worked on where a developer modified a DTO without thinking about the fact that his particular class wasn't the only one with a reference to that object.
    – Phil
    Sep 27, 2012 at 16:40
8

Maybe minor, but there's the risk of assigning this reference somewhere in one of the layers potentially causing a dangling reference or memory leak later on..

1
  • Your point is correct, but from OP's terminology ("passing object instances") I have a sense that either he is passing values (not pointers) or he was talking about a garbage-collected environment (Java, C#, Python, Go, ...). Jan 18, 2017 at 6:30
7

If you are passing objects around simply because it's needed in a remote area of your code, using the inversion of control and dependency injection design patterns along with optionally an appropriate IoC container can nicely solve problems regarding carrying object instances around. I've used it on a medium-sized project and would never again consider writing a large piece of server code without using it.

3
  • That sounds interesting, I already use constructor injection, and I think my high level components control the low level components. How do you use an IOC container to avoid carrying around instances?
    – Puckl
    Sep 27, 2012 at 17:44
  • I think I found the answer here: martinfowler.com/articles/injection.html
    – Puckl
    Sep 27, 2012 at 17:54
  • 1
    Side note, if you are working in Java, Guice is really nice, and you can scope your bindings to things like requests so that the high level component is creating the scope and binding the instances to the correct classes at that time.
    – Dave
    Oct 1, 2012 at 17:53
4

Passing data trough a bunch of layers isn't a bad thing, its really the only way a layered system can work without violating the layered structure. The sign there are problems is when you are passing your data around to several objects in the same layer to achieve your goal.

3

Quick Answer: There is nothing wrong in passing instances of objects. As also mentioned, point is to skip assigning this reference in all the layers potentially causing a dangling reference or memory leaks.

In our projects, we do use this practice to pass DTOs (Data transfer object) between layers and it is very helpful practice. We also do reuse our dto objects to construct more complex once, like for summary information.

3

I'm primarily a web UI dev but it sounds to me like your intuitive discomfort might be less about the instance pass-through and more about the fact that you're going a bit procedural with that controller. Should your controller be sweating all these details? Why does it even reference more than one other object's name for getting audio played?

In OOP design, I tend to think in terms of what's evergreen and what's more likely to be subject to change. The subject to change stuff is what you're going to want to tend to put in your larger object boxes so you can maintain consistent interfaces even as players change or new options are added. Or you find yourself wanting to swap audio objects or components therein wholesale.

In this case, your controller needs to identify that there's a need to play an audio file and then have a consistent/evergreen way of getting it played. The audio player stuff on the other hand could easily change as technology and platforms get altered or new choices are added. All of those details should sit underneath an interface of a larger composite object, IMO, and you shouldn't have to rewrite your controller when the details of how audio gets played change. Then when you pass an object instance with the details like file location into the larger object all that swapping around is done in the interior of an appropriate context where someone is less likely to do something silly with it.

So in this case I don't think it's that object instance getting tossed around that might be bugging you. It's that Captain Picard is running down to the engine room to turn the warp core on, running back up to the bridge to plot the coordinates, and then hitting the "punch-it" button after turning the shields on rather than simply saying "Take us to planet X at Warp 9. Make it so." and letting his crew sort out the details. Because when he handles it that way, he can captain any ship in the fleet without knowing the layout of every ship and how everything works. And that's ultimately the biggest OOP design win to shoot for, IMO.

2

It's quite a common design that ends up happening although you might have latency problems if your app is sensitive to that sort of thing.

2

This problem can be solved with dynamically scoped variables, if your language has them, or thread-local storage. These mechanisms let us associate some custom variables with an activation chain or thread of control, so that we don't have to pass these values around into code that has nothing to do with them just so that they can be communicated down to some other code which does need them.

2

As the other answers have pointed out, this is not an inherently poor design. It can create tight coupling between the nested classes and those that nest them, but loosening the coupling may not be a valid option if nesting the references provides a value to the design.

One possible solution is to "flatten" the nested references in the controller class.

Instead of passing a parameter several times through nested objects, you could maintain in the controller class references to all of the nested objects.

How exactly this is implemented (or if it is even a valid solution) is dependent on the current design of the system, such as:

  • Are you able to maintain some sort of map of the nested objects in the controller without it getting too complicated?
  • When you pass the parameter to the appropriate nested object, can the nested object recognize the parameter immediately, or was there additional functionality occurring while passing it through the nested objects?
  • etc.

This is an issue that I encountered in an MVC design pattern for a GXT client. Our GUI components contained nested GUI components for several layers. When the model data was updated, we ended-up passing it through the several layers until it reached the appropriate component(s). It created unwanted coupling between the GUI components because if we wanted a new GUI component class to accept model data, we had to create methods to update the model data in all of the GUI components that contained the new class.

To fix it, we maintained in the View class a map of references to all of the nested GUI components so that whenever the model data was updated, the View could send the updated model data directly to the GUI components that needed it, end of story. This worked well because there were only single instances of each GUI component. I could see it not working so well if there were multiple instances of some GUI components, making it difficult to identify which copy needed to be updated.

0

What you are describing is a called a Chain Of Responsibility design pattern. Apple uses this pattern for their event-handling system, for what it's worth.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.