Switch dataframe constructor to use dispatch
This is an attempt to add extensibility to the `DataFrame` constructor so that third party libraries can register their own ways of converting to a Pandas Dataframe. It does this by creating a [`singledispatch` function](https://docs.python.org/3/library/functools.html#functools.singledispatch) that is used in the constructor.

For example, Dask could implement the function like this:

```python
from pandas.core.construction import create_dataframe
import dask.datafame

@create_dataframe.register
def _create_dataframe_dask(data: dask.datafame.DataFrame, *args, **kwargs):
    return create_dataframe(data.compute(), *args, **kwargs)
```

Then, if a downstream library tries to construct a Pandas dataframe from a dask dataframe, it will work:

```python
import dask
import pandas

df = dask.datasets.timeseries()

assert isinstance(pandas.DataFrame(df), pandas.DataFrame)
```


This is response to [the thread about providing a protocol for dataframes](https://discuss.ossdata.org/t/a-dataframe-protocol-for-the-pydata-ecosystem/267) to present an alternative for the underlying use case. The alternative is:

1. Force libraries like sk learn to depend on pandas
2. Have them called `pandas.Dataframe` on their input data to see if it can be turned into a dataframe
3. Have third party libraries with alternative dataframe implementations register themselves with this function provided here.

It doesn't try to solve any sort of out-of-core dataframe API conversation and it does require all libraries to have Pandas as a hard dependency.

- [ ] closes #xxxx
- [x] tests added / passed
- [x] passes `black pandas`
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry
- [x] Review name of function

