The SitePoint Forums have moved.

You can now find them here.
This forum is now closed to new posts, but you can browse existing content.
You can find out more information about the move and how to open a new account (if necessary) here.
If you get stuck you can get support by emailing forums@sitepoint.com

If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

Objects using objects - I don't get it...

I don't for the life of me see how multiple classes can work together to produce a result without each of them being aware of the others.

And as they have to be aware of eachother - the problem is: how?

How does one object use another object?!

My nice address book application can create each object passing it the database object as a reference. Great, that's step one.

Now to use my email class I need to get the information from the database. Why? Well, having seperated everything into individual classes the simple $email->sendTo('westbroek') all of a sudden isn't simple anymore...

In order to $email->sendTo('westbroek') my email class needs to look up the name and find the email address.

How does $email do this? Does it create another object? How does it know about this object? From a config file?

The scope resolution operator looks so tempting but now doing names::getEmailAddress('westbroek') doesn't work. Why? Well, the database object passed by reference to the newly created names object doesn't exist because I'm not working with the object but with the class now.

Stuck again.

In the end the only solution I see is for all those classes which need to use one or more other classes to add code. Lots of it. "Ah, we need an address object .. let's see if it exists ... no, not in my namespace .... let's create it... if something goes wrong then.... blah blah blah"

The idea can't be that I put all objects which need to be used by other objects in the global namespace, is it?

Writing classes, components, seems so clear. Seems so to be the right solution. But somehow I cannot make a Car() from Body(), Wheels() and Motor().... I just end up with a bunch of tiny mini applications....

Class names are intrinsicly global. This means that any class can create an instance of another at will. However this is not usually a good idea unless such classes are very closely related. Here are all the options that I can think of...

1) Pass it in as needed in the method. This is the approach with the least coupling and so, if you can, you want to do this as a first choice...

This is handy if you are going to call more than just the paint() method and the writer will be needed in each case. Duplication is bad and this avoids it. This is called the Strategy pattern and the tool of choice in OO.

This is marginally better, because now other developers can subclass the Template and override createWriter() to return a different kind of writer. However you can only inherit once so this allows only one option per class. It also won't help if Template itself is inherited from something more complicated. Things just get too tangled. The pattern itself is called TemplateMethod or sometimes "programming by differences".

5) Pass in a factory. This is very highly factored solution and will solve even the most complex of cases...

You rarely need this much firepower, but once you are used to the idiom itis quite clean. Use this especially when you want to completely swap out the infrastructure of a system. That is you are not just changing the writer but other parts as well as a group. For example a command line infrastructure would have a TextWriter and might have getArguments() return the $argv values rather than $_REQUEST. The pattern is called the AbstractFactory when it creates families.

This is a classic case of people copying Java idioms without thinking. There are language restrictions in Java regarding the number of public classes and tricks involving the use of inner classes to avoid exposing too many interfaces. These idioms are unnecessary and unavailable in PHP. This trick buys nothing that the "new" operator doesn't give you already, other than the ability to change the delivered class by editing the code in just one place. Completely useless and yet you see it all over the place.

7) Make the object global. This is so bad I find it painful to even type in the example...

The chances of accidents happening heads rapidly to 100% on any project that is remotely complicated. Besides some other method overwriting the global, you have to make sure it is properly set up once only before you use it. Programers will come up with all sorts of naming conventions and practices to prevent accidents not realising that they are creating more work than if they just added some design. When the disaster occours anyway, debugging is a nightmare.

8) The Singleton pattern is a very clever way to implement a global. Basically this is a static method that returns only one instance. You might want to do this when you only want one object created ever, either because of creation cost or because it needs a memory. A database connection is a good example because it usually has to keep track of transactions. Here is the writer again. Imagine it has to send some headers once only on first use...

By hiding the variable inside a "closure", here named getInstance(), you ensure it can only be accessed via that method. This ensures that it is read only and that it is correctly set up. A clever little pattern, but the static method makes this pattern very inflexible. It also makes the application difficult to test because, that single instance is impossible to reset between each test. Code that you cannot test is probably broken and the Singleton these days has a bad reputation.

9) The registry, which usually forms the basis of "dependency injection", is a major upgrade to the Singleton. Essentially the registry object is the singleton to which you add the global services...

You have to ensure that the registry entry is set up before it is used of course. The advantages of teh registry approach is that the registry can be set up differently for each and every test in your test scripts, and that additional flexibility can be added as needed such as a lookup order for a resource. This is a complex solution to say the least.

I have probably missed a few, but that should give you enough options.

Is it a good idea to combine these in one factory-like class which is responsible for creating any class you want? Per create method you could then decide/program if it should be a singleton or in a registry?

It seems to be that delegating the actual task of creating an object to one central class makes the coupling of classes easier? At the same time each class would know less about the actual object needed: if I want to change Addresses for Cities I can do so in that factory class?

...

It reads like an idea to me. To use Factory::createNames() and the like everywhere.

Personally I find this the hardest part ... the talking of objects to eachother.

If I understand well then moving the creation of additionally needed objects outside of your worker classes is a good idea.

PHP Code:

class Factory {

function Factory() {
}

function createNames() {}

function createAddresses() {}

etc.

}

One more question then: is it a sign of good or bad design if classes rely heavily on other classes? I would say it is good as in 'each object does what ti does best', on the other hand I would say bad as each object needs to know more and more about the other object, right?

If I understand well then moving the creation of additionally needed objects outside of your worker classes is a good idea.

Not necessarily. That means you are exposing the passed object in the calling script. It's better not to do that unless you have a good reason to do so. Encapsulation means jealously guarding as much as possible behind an interface. Exactly what to do would depend on the specific case. You might need to weave the second object into other parts of the code in which case you'll want to pass it in.

Incidentally, the internal factory method in Lastcraft's example (4) is good for testing since you can create a partial mock of the main class and then return a mock object from the factory method (which you knocked out with the partial mock). You can set return values and expectations for the mocked factory object in order to investigate its interaction with the main class. If you're not testing already, that's not as complicated as it sounds.

Originally Posted by westbroek

is it a sign of good or bad design if classes rely heavily on other classes? I would say it is good as in 'each object does what it does best', on the other hand I would say bad as each object needs to know more and more about the other object, right?

Objects have to talk to each other - but no more than they have to. I'd recommend trying test driven design. This helps you to focus on the interface of the class being tested as well as its immediate neighbours, and how they should interact.

I'd recommend trying test driven design. This helps you to focus on the interface of the class being tested as well as its immediate neighbours, and how they should interact.

That has to be the single best recommendation ever - and one of the best links on the case, for a newcomer to testing.

I've come across references to Simple Test but it didn't seem tempting. Boy, did I miss out! I've been playing around for several hours now, together with the article you linked to, and this is brilliant! Thank you Marcus for writing this!

Who would have thought that doing it the other way around, write the test first, would make so much more sense and clarify so much!? Wow.

<added> See, just now I did a db class with connection parameters in the constructor and a table class which extends the db class. Doing it step by step using Simple Test I quickly learned that testCreateTable() errored on the missing db connection info... put a db::db(connection info) in the table class... test works... let's try if I can move that out of there to another point... test fails... In 2 or 3 minutes time I prevented myself from making a (stupid) mistake I would otherwise not see ...

Testing before coding feels like the extended version of inline syntax error highlighting.... </added>

What I find bugging with these other creation methods is that my editor doesn't show me the methods available in a class anymore

Originally Posted by McGruff

It is one of those eureka moments, isn't it

You have no idea... or maybe you do I feel like I skipped several classes, trials & errors and have jumped to another level all together.

At first I followed the examples very, very close. Then now in the last couple of hours I've written a bunch of tests for several conditions and situations and from those tests I was able to see how I best could implement all those together. In one case I ended up with a class but with something I wrote just now I ended up with a function library.

The tests remind me a bit of user persona in designing web sites. I think they're called User Stories in programming design patterns.

Originally Posted by Dr Livingstone

Domain Driven Design

You know, my problem with design is recognizing design from buzzwords and buzzconcepts. 2-3 years ago when I started to read up on OOP passing the database object in the constructor of another object was old school. Non-OOP almost. Now it is OK, almost new school, and you could call it Dependency Injection.

I spoke with another programmer, a serious one, on an SEO forum the other day. He has been using this testing a longer time and said to forget about reading up on design patterns: the tests will show you how something should be implented.

I think I see where your friend is coming from but I wouldn't abandon studying design patterns altogether. I think there are a lot of useful ideas and concepts to be found - and it provides a common vocabulary to discuss design ideas.

I find testing is a whole lot of fun at times. Every now and then when something's not working you can just try a wild guess at how to fix it without fully understanding what's going on. Sometimes you get lucky and it works, saving you taking the time to figure it out properly. If you've got the green bar it must be correct.