REF: de-duplicate DataFrame/SparseDataFrame arithmetic code
Not quite all the way de-duplicated, but this is as much as I could do without it getting convoluted.
Hello @jbrockmendel! Thanks for submitting the PR.

 - There are no PEP8 issues in the file [`pandas/core/frame.py`](https://github.com/jbrockmendel/pandas/blob/7810dc694ebb84f0afcd37452350a0f5c0dd6f04/pandas/core/frame.py) !

 - There are no PEP8 issues in the file [`pandas/core/ops.py`](https://github.com/jbrockmendel/pandas/blob/7810dc694ebb84f0afcd37452350a0f5c0dd6f04/pandas/core/ops.py) !

 - There are no PEP8 issues in the file [`pandas/core/sparse/frame.py`](https://github.com/jbrockmendel/pandas/blob/7810dc694ebb84f0afcd37452350a0f5c0dd6f04/pandas/core/sparse/frame.py) !

 # [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/23414?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@592fd64`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `97.22%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/23414/graphs/tree.svg?width=650&token=eZ4WkYLtcO&height=150&src=pr)](https://codecov.io/gh/pandas-dev/pandas/pull/23414?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##             master   #23414   +/-   ##
=========================================
  Coverage          ?   92.23%           
=========================================
  Files             ?      161           
  Lines             ?    51324           
  Branches          ?        0           
=========================================
  Hits              ?    47338           
  Misses            ?     3986           
  Partials          ?        0
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.62% <97.22%> (?)` | |
| #single | `42.3% <22.22%> (?)` | |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/23414?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/sparse/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/23414/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvc3BhcnNlL2ZyYW1lLnB5) | `94.64% <100%> (ø)` | |
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/23414/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `97.03% <100%> (ø)` | |
| [pandas/core/ops.py](https://codecov.io/gh/pandas-dev/pandas/pull/23414/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvb3BzLnB5) | `94.24% <80%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/23414?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/23414?src=pr&el=footer). Last update [592fd64...7ecb03f](https://codecov.io/gh/pandas-dev/pandas/pull/23414?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
 > this is too much special casing on the dispatch function, pls try to unify these.

The two versions of this method are:

```
    def _wrap_dispatched_op(self, result, other, func, axis=None):
        result = self._constructor(result, index=self.index, copy=False)
        result.columns = self.columns
        return result

    def _wrap_dispatched_op(self, result, other, func, axis=None):
        fill_value = self._get_op_result_fill_value(other, func, axis)

        res = self._constructor(result, index=self.index,
                                columns=self.columns,
                                default_fill_value=fill_value)

        return res.__finalize__(self)
```

The only way I can see to combine these would be:

```
    def _wrap_dispatched_op(self, result, other, func, axis=None):
        if isinstance(self, ABCSparseDataFrame):
            [the version currently in SparseDataFrame]
        else:
            [the version currently in DataFrame]
```

The point of implementing this method is because it is the part of the apply_index/apply_columns/etc that _cant_ be shared.  With this in place, then we have a real shot at de-duplicating the rest of those methods. can merge master and i'll look again. The actually-useful step is the one after this: using _wrap_dispatched_op to make SparseDataFrame._combine_frmae, _combine_match_index, _combine_match_columns, and _combine_const unncessary.  But for reasons I'm not clear on, doing so breaks a bunch of tests.  Since SparseDataFrame may be on its way out anyway, closing.