There are actually two modes of operation: dynamic and static. This applies both to Visualforce and Apex Code.
In static mode, tight coupling of the MVC layers prevents administrators from accidentally changing any later that would break the other layers. For example, you can't delete a field that is used in a controller. Also, the packaging system can resolve static references to classes, fields, etc, greatly increasing the chance that deployments will be successful the first time around.
In dynamic mode, loose coupling of the MVC layers allows the view and controller layers to dynamically determine which object and field to use. This has a distinct downside; the looser coupling can allow fields referenced indirectly to be modified or deleted, which can cause pages to fail, and can prevent the packager from correctly determining which fields should be included with the package.
While it is true that there are some features that are necessarily bound statically (
standardController is one of them), multiple pages using different standard controllers can all use the same extensions, assuming the extension is capable of dynamically determining which object it should be using (the system has tools to allow this discovery, but the developer has to intentionally code this flexibility into the controller). Combined with custom components, one can still achieve a high level of flexibility and code reuse.