Skip to content

Implement interface and delegate calls to decoratee #572

@baks

Description

@baks

Sometimes, we may want to implement a decorator pattern. If the interface is large, there is a lot of repetitive work because we must delegate call for each method. We could make refactoring that simplifies this task.

Given following code:

        public interface ICalculator
        {
            void Add();
            void Multiply();
            void Subtract();
            void Divide();
        }

        public class LoggingCalculator : ICalculator
        {

        }

And caret is on ICalculator in base type list of LoggingCalculator class
When user selects Implement interface and delegate calls to decoratee refactoring
Then code is refactored :

    public interface ICalculator
    {
         void Add();
         void Multiply();
         void Subtract();
         void Divide();
    }

    public class LoggingCalculator : ICalculator
    {
        private readonly ICalculator calculator;

        public LoggingCalculator(ICalculator calculator)
        {
            if (calculator == null)
            {
                throw new ArgumentNullException(nameof(calculator));
            }
            this.calculator = calculator;
        }

        public void Add()
        {
            calculator.Add();
        }

        public void Multiply()
        {
            calculator.Multiply();
        }

        public void Subtract()
        {
            calculator.Subtract();
        }

        public void Divide()
        {
            calculator.Divide();
        }
    }

We can also offer similar refactoring to deal with abstract classes:

    public abstract class Calculator
    {
        public abstract void Add();
        public abstract void Multiply();
        public abstract void Subtract();
        public abstract void Divide();
    }

    public class LoggingCalculator : Calculator
    {
        private readonly Calculator calculator;

        public LoggingCalculator(Calculator calculator)
        {
            if (calculator == null)
            {
                throw new ArgumentNullException(nameof(calculator));
            }
            this.calculator = calculator;
        }

        public override void Add()
        {
            calculator.Add();
        }

        public override void Multiply()
        {
            calculator.Multiply();
        }

        public override void Subtract()
        {
            calculator.Subtract();
        }

        public override void Divide()
        {
            calculator.Divide();
        }
    }

Severity : Hidden
Category: Refactoring
Diagnostic Id: CC0109

Visual Studio offers similar refactoring but it only does it if you declare a field inside a class with the same type of the interface to be implemented.
For me, this is still improvement if this refactoring would be introduced in presented form to the code-cracker. @code-cracker/owners, I think we can start discussion and figure out if this is a valuable refactoring.

I also blogged about motivation for this refactoring here

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions