Also read Why is Object Oriented Programming good for Crystallographic Computing ?.
Overview of the Library (Crystallographic classes)
All Scatterer can be derived from such a class: Atom, ZScatterer. The advantage of using inheritance is that all derived classes must re-use the functions declared in the base class, so that any function which knows what a generic 'Scatterer' object (but does not know what an Atom or ZScatterer is) can still use any derived class.
Further development example: currently there is no 'rigid body' object: if any developper wants to create such an object, he just needs to make sure he rewrites the function GetScatteringComponentList(). Thus without any modification, the Crystal and ScatteringData classes will automatically be able to use this new object... since this RigidBody object is derived from the Scatterer class (which Crystal and ScatteringData know).
The base class is designed to handle anisotropic factors: for this the index of the symetric position in the Spacegroup must be given.
Further development example: currently only the interface to handle anisotropy has been written, but no code or derived class. But no matter what kind of anisotropy is added, it will always work with the base class interface.
Note: why always use a ScatteringData object as input (to compute scattering factors, for example), rather than, say, a list of HKL or a list of sin(theta/lambda) ? The first reason is that from a ScatteringData you can extract all these hkl's and sin(theta)/lambda. The second reason is that with such an approach, no matter how complex the derived classes are, you can always use the same interface (for isotropic thermic factors as well as anharmonic !), so that any function written with only the knowledge of the base class can use any derived class.
This design does not mean that only 'stupid' algorithms can be handled. Since the 'random moves' are handled by the refined objects, this 'random moves' can be very non-random (for example in the Crystal object, permutation of Scatterers is made from time to time...).
What if you are not interested in the RefinableObj functionnality ? You can simply ignore it, it will not do any harm. You can do other crystallographic work by 'forgetting' that a Crystal, PowderPattern, Atom is a RefinableObj. Even new derived objects do not have to declare their parameters as 'RefinablePar', if you want to save some memory.
what is currently lacking in RefinableObj is (i) a way to set constraints/restraints (currently there are only limits for individual parameters), the ability to have arrays of RefinablePar (to handle large structure without a significant memory penalty), and a design for analytical derivatives (well I've got a few ideas about this but this is not a priority yet...).