These derived types contain data that is not in model or observation space.
As a first implementation, a Locations type could contain two obs_data entities (or something based on the same structure) that can be filled with latitudes and longitudes read from an obs_space object. In the longer term, more complex locations will be needed (slanted profile, satellite footprint, GPSRO line of sight...). A random method might be useful for testing of interpolations, however, it has to be compatible with the type of application being tested (global, LAM, ocean, etc...). A quick and dirty implementation could be to wrap the whole obs_space object.
Variables can be implemented in many ways. The cleanest would be an actual list of varaibles (for example based on the NetCDF CF or GRIB conventions). It could also be a much more model specific derived type containing flags or anything necessary to know what fields are required by the model if the state is going to be used as an initial condition, or what variables are needed by an observation operator when the Variables is used as an input to the interpolations.
fields_at_locations could be seen as a state with an unstructured geometry. However, it cannot be substituted for a state as initial condition for a forecast. In many applications, it will contain values distributed geographically or an unstructured grid, but also distributed in time so it does not have a valid time like a state would have. For these reasons, it cannot be a sub-class of state.
Most constructors take a configuration parameter (type config). This represents user input, typically what would be read from namelists in traditional fortran. Instances could contain actual values to be used inside the routines, or at least information for lower level fortran code to read in the proper namelists. When writing a constructor (or other method that need user configuration), one cannot assume that only one instance will be created or that all instances will be created from the same parameter. That information can only come from higher level code, even if that information is only the name of a file where to read namelists from.