You can e.g. compile the same vertex shader 3 times and link it to 3 different fragment shaders to make 3 different program objects, and all of this can be done once-only at startup, meaning that calls to glLinkProgram at runtime are unnecessary (just make the appropriate glUseProgram call instead). Also look at GL_ARB_separate_shader_objects (standard in GL4.1+) for another method of doing this.
That's a good idea, but is it generally understood that there's a performance benefit to this? Let's say I want to draw to two separate framebuffer objects. When switching programs between them, I also have to send all the uniforms again. If I just use one shader with if(), I only have to update one uniform (whatever pass I'm on).
The if/else way seems much more convenient, but if it's possible there's a performance benefit to switching programs, that's worth consideration.