OO programming takes a while to get up to speed with. There's not only the idea of using objects, but you also need to use a bunch of design patterns to solve various problems that are commonly encountered. There isn't "one true way" to do OO and there are very few recipes for getting started. Because of this it can get easy to get so caught up in all the new concepts that it becomes really difficult to get it all straight and get a good architecture.
One thing I've learnt from TDD and agile is the idea of doing the simplest thing possible - anything more complex is probably wrong anyway :-)
I find now that while I'll try to get some ideas about architecting something, if I'm unsure how to solve a problem correctly, I'll just hack any old solution that works. As I add more scenarios, I'll see good candidates for refactoring and will user that to evolve my class model and API.
There are a bunch of benefits to a refactoring approach. Firstly, you're never that far outside of your comfort zone so the process is much more comfortable than trying to get the ideal architecture upfront. Secondly you get working code quickly. Thirdly you don't get stuck in analysis paralysis - you just get something working and then improve it. Fourthly, your don't end up building a huge edifice you'll never end up using.
A while back I was trying to come up with "THE validation framework" that I could use for all of my validations. I came up with an extremely complex system that ended up not working terribly well when I tried to use it within my framework. This time round I'm just hand coding validations within my objects and slowly refactoring those to a set of validation helper methods that I'm going to compose within my beans. By starting with hard coded validations, I'm getting working code quickly, and by refactoring only to implement real use cases, I know that the API works better than anything I could develop in the abstract.
So, if you're trying to design something, consider coming up with a nice simple scenario and coding the simplest tests and then code required to implement the scenario. Let me know your experience, but I've found this approach to make it much easier and more enjoyable to create elegant code.