**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
"""Adds only new items to item set"""
        if item in item_set:
            self.log.warning(
                'Dependency %s, %s already registered', self, item)
        else:
            item_set.add(item)
    def _set_relatives(self,
                       task_or_task_list: Union['BaseOperator', Sequence['BaseOperator']],
                       upstream: bool = False) -> None:
        """Sets relatives for the task or task list."""
        from airflow.models.xcom_arg import XComArg
        if isinstance(task_or_task_list, XComArg):
            
            
            
            task_list = [task_or_task_list.operator]
        else:
            try:
                task_list = list(task_or_task_list)  
            except TypeError:
                task_list = [task_or_task_list]  
            task_list = [
                t.operator if isinstance(t, XComArg) else t
                for t in task_list
            ]
        for task in task_list:
            if not isinstance(task, BaseOperator):
                raise AirflowException(