REF: put EA concat logic in _concat_arrays
cc @jorisvandenbossche @TomAugspurger per discussion in #32586 (among others) about `_concat_same_type`, this is a proof of concept for a 3-method solution:

- `EA._concat_same_dtype` --> require same type _and_ dtype; DTA/PA do this now
- `EA._concat_same_type` --> require same type but not necessarily same type; we could do without this, but since its already in the API...
- `EA._concat_arrays` --> any ndarray/EAs

For example, `dtypes.concat._concat_sparse` naturally becomes `SparseArray._concat_arrays`.  The middle chunk of `union_categoricals` becomes `Categorical._concat_same_dtype`. 

Everything described above is just a refactor, putting logic in more reasonable places.  The benefit interface-wise is that the dispatching in `concat_compat` looks like

```
if we_have_any_categoricals:
    return Categorical._concat_arrays(to_concat)
elif we_have_any_datetimelike:
    return DatetimeLike._concat_arrays(to_concat)
elif we_have_any_sparse:
    return SparseArray._concat_arrays(to_concat)
[...]
```

ATM the order Categorical -> DTA/TDA/PA -> Sparse is hard-coded, but we could generalize this either with a negotiation logic like Tom [described](https://github.com/pandas-dev/pandas/issues/22994#issuecomment-436279333) or with something simpler like defining `EA.__concat_priority__ = 1, Categorical.__concat_priority__ = 1000, [...]` and the dispatch becomes:

```
eas = {type(x) for x in to_concat if isinstance(x, ExtensionArray)}
eas = list(eas)
eas.sort(lambda x: x.__concat_priority__)

if eas:
    return eas[-1]._concat_arrays(to_concat)
```