An attack is an action, a verb. You should not model verbs as nouns, or else you end up with anathemata like attack.do(hero, enemy) instead of a more natural hero.attack(enemy). Attack handlers, attack events, attack objects: what do those look like in real life?
Modeling your code components after real life, physical objects is, in my view, an antipattern. In a good design some components may conceptually align with an object in the physical world or the simulation you are creating, but whether or not a component correlates with one of those objects should not be a requirement. After all , what does a database transaction look like? What does a file stream look like? What does a dependency injection container look like?