**Description**

Currently `BaseOperator` and `XComArgs` implements the same logic of `__lshift__`, `__rshift__` and others "chain" operations (`>>`, `<<`). It seems resonable to abstract this logic into `TaskMixin` to introduce some DRYness especially because the new concept of `TaskGroup` will also implement the same methods.

**Use case / motivation**

Limit duplication of logic.

**Related Issues**

https://github.com/apache/airflow/pull/10827#issuecomment-691927501
#10153 

airflow/models/baseoperator.py
to_tasks: Union[BaseOperator, Sequence[BaseOperator]]):
    r"""
    Set downstream dependencies for all tasks in from_tasks to all tasks in to_tasks.
    .. code-block:: python
        cross_downstream(from_tasks=[t1, t2, t3], to_tasks=[t4, t5, t6])
    is equivalent to::
        t1 ---> t4
           \ /
        t2 -X -> t5
           / \
        t3 ---> t6
    .. code-block:: python
        t1.set_downstream(t4)
        t1.set_downstream(t5)
        t1.set_downstream(t6)
        t2.set_downstream(t4)
        t2.set_downstream(t5)
        t2.set_downstream(t6)
        t3.set_downstream(t4)
        t3.set_downstream(t5)
        t3.set_downstream(t6)
    :param from_tasks: List of tasks to start from.
    :type from_tasks: List[airflow.models.BaseOperator]
    :param to_tasks: List of tasks to set as downstream dependencies.
    :type to_tasks: List[airflow.models.BaseOperator]
    """
    for task in from_tasks:
        task.set_downstream(to_tasks)
@attr.s(auto_attribs=True)
class BaseOperatorLink(metaclass=ABCMeta):