Sourdough is a factory driven framework using a flyweight pattern in its basic design. Like this, you are able to use Sourdough in an efficient way, even if you make just usage of a very small part of the framework.
When we talk about the Flyweight Pattern, we refer to the definition of the GOF (Gang-Of-Four):
The Flyweight Pattern uses sharing to support large numbers of fine-grained objects efficiently. A flyweight is a shared object that can be used in multiple contexts simultaneously. The flyweight acts as an independent object in each context — it's indistinguishable from an instance of the object that's not shared. Flyweights cannot make assumptions about the context in which they operate.
Basically, there is a FlyweightFactory object that acts as a global manager. It manages the instantiation of each requested object. The client (in our case e.g. the web-application that is based on Sourdough) gets object instances through this global manager. The manager then decides wether it should return a singleton of an object or a new object on each call. The following UML digram tries to simplify this:
To get more specific, in Sourdough, there is a global object that manages everything. It's Sourdough's main class Sourdough which must be instantiated on the first usage. The client then accesses every single object through this global manager. It requests an object, the manager includes the necessary files, resolves existing dependencies, and finally returns the object to the client.
The following diagram shows a part of Sourdough's structure. Sourdough plays the global manager and on the right side you see some classes of various packages, their inheritance, and their dependencies.
For detailed class description, please refer to the API documentation.