In my implementation I have two layers - stat modifiers and effects. Stat modifier may be caused by effect, but effects can do much much more (anything really, from various disease effects, to just lowering certain stats). So the idea is that effect has start_effect() and remove_effect() methods which in case of pure stat modifiers are the ones responsible for adding and removing them. So it looks a bit like this (some Angelscript pseudocode):
class NastyDisease: Effect
StatModifier @str_mod, @vit_mod;
void start_effect(object target)
@str_mod = target->add_stat_modifier(Stat::Strength, -20);
@vit_mod = target->add_stat_modifier(Stat::Vitality, -30);
// Called when effect expires
void remove_effect(object target)
This makes StatModifier class just a dumb storage for how much and what stat is modified, and the expiration is handled by Effect class (on a usual timer basis, I don't check upon requsting stat that I should remove some modifier, if the effect expires appropriate function is called and it removes these modifiers.
There is slight problem with this, because if something goes wrong in remove_effect() function (runtime error), it may keep the effects on the player, but I guess if that happens something is really wrong.