At a higher level, a plugin architecture should fulfil at least the following requirements:
Extensibility: The main idea behind plugins is to allow the extension of the core functionality using isolated bundles of code. A great plugin architecture allows you to extend the core seamlessly and without noticeable performance losses.
Portability: Plugins should be isolated enough so that they can be plugged into the system during runtime. There shouldn't be a necessity to rebuild a system to enable plugins. Ideally, plugins can even be loaded at any time during runtime. They can be deactivated and activated and should not cause the system to run into an inconsistent state.
Composability: A plugin system should allow the use of many plugins in parallel and allow an extension of the system by compositing multiple plugins together. Ideally, the system also includes dependency management, plugin version management, and plugin intercommunication.
There are a lot of different approaches...