To summarize,
- A state diagram shows the behavior of a single object across several use cases.
- Sequence diagrams are useful for examining the behavior of several objects in a given use case.
- Activity diagrams are concerned with behavior of many objects across many use cases.
I go into further depth here. Unless otherwise stated, the diagrams are all drawn from Wikipedia.
State Diagrams
This is an example everybody should be familiar with: a door. A door can be in one or two states: opened or closed. (Let's just assume ajar counts as open)
These two states are indicated by green circles.
Furthermore, it is possible to transition between states under certain transition conditions. For example, opening the door causes a closed door to become open. Enough said.
Activity diagram
The above diagram is taken from UML Distilled, which is in my opinion an excellent book.
It depicts how a company processes orders. We start from the top, when the company receives an order. (Again, what causes an order to be received is unknown). Thereafter, there is a fork. The two branches are separate and can be executed in parallel. In layman terms, it doesn't matter whether the order is filled before, after, or while the invoice is sent.
Also, diamonds indicate decisions. When one arrow points into the diamond and several arrows point outwards, it is the start of the "if-else" condition, when the converse happens, it is the end of the "if-else" condition.
Next, just before "Close Order", we have join. This means that "Close Order" will be taken only when both the Fill Order and Send Invoice branches are complete.
Sequence diagram
This is relatively easy to understand. Just read downwards. First of all, notice that there are two participants: Computer and Server.
This raises an interesting question. Will newEmail be sent immediately after sendUnsentEmail has been sent? Or will it have to wait for sendUnsentEmail to finish executing? It turns out that this depends on a very small detail. Here, the arrowhead for sendUnsentEmail is a filled arrowhead, which means that newEmail will only be sent after the previous message has been processed. (In technical terms, this is known as a synchronous message) If it had been an unfilled arrowhead (e.g. the arrowhead of the "response" arrow), then it would have been an asynchronous message, and newEmail would be sent immediately after sendUnsentEmail's execution.