In my company we get on and off shore contractors in and out all the time. It is hard to maintain a code base like that since the level of maturity in writing code varies considerably. To a certain extent my role consists of mentoring the development resources. I have found that if I just let them code, i will get something very naive put together. What is the best way to teach people who are already developers how and when to use interfaces, abstraction, wrapping, design patterns, reflection etc.
Your answer is in your question. The only way I have found to do it is to mentor younger developers, one at a time. That means matching developer ability to project difficulty, and spending time guiding them in the right direction.
Edit: Looking back at your question, I think maybe my answer is not so good. Unless they are long term (and probably not offshore), I don't think you are going to have much luck mentoring contractors. You are going to get what you get. Keep that in mind when you hire.
Make everyone start with maintenance. Only by learning how painful maintenance is on bad code is can you learn not only how to write good code, but also have the incentive to actually do so.
Your question is bigger than programming and IT, of course -- it really gets into the heart of teaching theory -- how best to pass on knowledge from one person to another.
We know some of the basics -- small student to teacher ratio, etc. And you can't do the work for the student if you want them to master something.
So, what can we take away from this? Make sure you have consistent standards of where you want your "students" to get to. Ensure that you have quality materials they can learn from. You have to have a methodology to do this, otherwise you'll find that you're wasting a LOT of your own precious time. Mentoring is vitally important, but again, your student is going to need to have the wherewithal to learn on their own after being pointed down the right direction.
So how DO you teaching the import programming concepts that go way beyond syntax?
Personally, I like mentoring and providing good examples the junior developer can delve into to learn the ins and outs for themselves.
And don't forget that they need room to make mistakes, but those mistakes have to be caught and corrected.
I'd suggest making sure that code reviews are somehow incorporated into your development process. Not the confrontational kind (two or more reviewers gather with the coder in a meeting room, with the result of tearing him to shreds), but more the one-on-one, walking through of what's been written. From what you described, it sounds like your developers are geographically distant, thus making an effective code review difficult. However, persevering in this would be worthwhile. A real-time voice conversation, with the code in front of both of you, would be best, if you can't get together in person.
As long as you enter into such reviews with the goal of helping your developers to get better, both of you will benefit.
"Teaching" may not be the proper approach for what you want. You want them to use the knowledge and to make things better and constantly be doing that is a slightly different way to view things. What kind of reputation do the developers have? What kinds of benefits do they get if they do use interfaces, abstraction, wrapping, design patterns, reflection, etc. in the way you want? What kinds of benefits would they want? That's the questions that come to mind as sometimes if you can find what motivates someone, that is the key rather than merely assuming that the issue is in "Technique." For more on the difference, take a look at this article at "Sources of Insight" which is excellent blog about patterns and practices, IMO.
Pair programming is excellent for this, as it is like a continuous code review. The junior will learn SOOOOO much from the senior about design: "interfaces, abstraction, wrapping, design patterns, reflection etc."