OO instance and where to put the implementation (logical part)

I can put an implementation within the following OO elements:

  1. Object
  2. Class
  3. Trait
  4. Case Class

Also so far I know:

  1. Object is singleton, and class isn’t. So if we want one instance we use object.
  2. Use the combination of trait and class if I want to use the trait as an interface.
  3. Can use companion object for a class, to hold the values/data models.

Outside these three, I think there are a lot more to look at. Is there any “set of rules” I need to be aware of solely based on the OO principles in Scala?