This question is hard to answer without knowing exactly what your game system does and does not allows your "jobs" to do.
But usually I would use composition instead of inheritance. There would be just one class
Job. Each instance of
Job has a
List<Skill> skills (or other appropriate data-structure). You are not saying much about what "do certain tasks" actually means in your game. Does each skill represent exactly one task which the player can perform with some input action? Then
Skill would have an abstract method
performOn(GameObject target). Or can a skill actually provide more than one task? Maybe even depending on some other factors? Then
Skill might need a method which returns a
But either way, I would try to use as few classes inheriting from
Skill as possible. Skills with similar functionality should use the same class with different values.
For example, let's say you have skills like
Fishing. Having one of those skills allows the player to perform the "extract resource from resource node" task and this task is mechanically identical for each skill. They just differ by the kind of node they work on. I that case I would just have one class
ResourceGatheringSkill inheriting from
Skill. The different instances of this class would differ by a property which says which resource nodes it works on.
You could even go a step further and move the logic to decide what can and can not be gathered to the resource nodes. In that case the resource gathering skills become even simpler. The script on the resource nodes would just check if the job of the player-character has a skill with a specific name. In that case
Skill would just need a property
name, nothing more.