简体   繁体   中英

Signature of interface's method includes a class, which implements the interface itself

Considering the rules of good OOP and design, is it correct to write a method in an interface which has as input types or output types classes which implements the interface?

I give you an example of a very simple exercise I must do, regarding complex numbers:

public interface IComplex
{
    double GetImaginary();

    double GetReal();
    
    ComplexImpl Conjugate();

    ComplexImpl Add(ComplexImpl y);

}

/*----------------------------------------------------*/


public class ComplexImpl : IComplex
    {
    private double real;

    private double imaginary;

    public ComplexImpl(double real, double imaginary) { this.real = real; this.imaginary = imaginary; }

    public double GetReal() { return this.real; }

    public double GetImaginary() { return this.imaginary; }

    public ComplexImpl Conjugate()
    {
        ComplexImpl conjugate = new ComplexImpl(this.real, -this.imaginary);
        return conjugate;
    }

    public ComplexImpl Add(ComplexImpl y)
    {
        ComplexImpl result = new ComplexImpl(this.real + y.real, this.imaginary + y.imaginary);
        return result;

    }

}

Considering the interface IComplex : is it correct to write the methods Conjugate and Add such that they have as input (and/or output) objects which are instantiations of the class ComplexImpl?

Consider that the class ComplexImpl implements the interface when this methods are defined.

EDIT :

For those of you who answer: first of all thank you, however I have the following problem. If I substitute "ComplexImpl" with "IComplex" both in the interface and in the class, I obtain this error in the method Add :

" 'IComplex' does not contain a definition for 'imaginary' and no accessible extension method 'imaginary' accepting a first argument of type 'IComplex' could be found ".

The only way to solve this is through the use of Generics?

I suggest you use the interface IComplex instead of ComplexImpl in the interface. This will still yield the desired results without relying on an implementation of the interface.

public interface IComplex
{
    double GetImaginary();

    double GetReal();
    
    IComplex Conjugate();

    IComplex Add(IComplex y);

}

This will be your concrete type implementation:


        public class ComplexImpl : IComplex
        {
            private double real;

            private double imaginary;

            public ComplexImpl(double real, double imaginary) { this.real = real; this.imaginary = imaginary; }

            public double GetReal() { return this.real; }

            public double GetImaginary() { return this.imaginary; }

            public IComplex Conjugate()
            {
                ComplexImpl conjugate = new ComplexImpl(this.real, -this.imaginary);
                return conjugate;
            }

            public IComplex Add(IComplex y)
            {
                ComplexImpl result = new ComplexImpl(this.real + y.GetReal(), this.imaginary + y.GetImaginary());
                return result;

            }

        }

Note that you cannot access private members when referring to an interface. All interface definitions are public . Therefore you cannot use y.imaginary for example but since the interface defines an accessor for this private field GetImaginary() , you can use that.

This thing is breaking the reason to use interfaces: To abstract implemntations. An easy and bearable fix to this would be:

public interface IComplex
{
   double GetImaginary();

   double GetReal();

   IComplex Conjugate();

   IComplex Add(IComplex y);

}

This way an implmentation is returned, but the interface stays clean and has no knowledge about an implementation.

You can make the interface or methods generic, constrained over your interface.

Choice 1

public interface IComplex<TComplex>
    where TComplex : IComplex
{
    double GetImaginary();

    double GetReal();
    
    TComplex Conjugate();

    TComplex Add(TComplex y);
}

Choice 2

public interface IComplex
{
    double GetImaginary();

    double GetReal();
    
    TComplex Conjugate<TComplex>() where TComplex : IComplex;

    TComplext Add<TComplex>(TComplex y) where TComplex : IComplex;
}

I think a better design would be to use IComplex in the method signatures in the interface:

public interface IComplex
{   
    double GetImaginary();

    double GetReal();


    // Changed:
    
    IComplex Conjugate();

    IComplex Add(IComplex y);
}

and call .GetReal() and .GetImaginary() (rather than getting the real and imaginary values directly) inside both Conjuate() and Add() :

public class ComplexImpl : IComplex
{
    private double real;

    private double imaginary;

    public ComplexImpl(double real, double imaginary)
    {
        this.real = real;
        this.imaginary = imaginary;
    }

    public double GetReal() { return this.real; }

    public double GetImaginary() { return this.imaginary; }


    // Changed:

    public IComplex Conjugate()
    {
        ComplexImpl conjugate = new ComplexImpl(this.GetReal(), -this.GetImaginary());

        return conjugate;
    }

    public IComplex Add(IComplex y)
    {
        ComplexImpl result = new ComplexImpl(
            this.GetReal() + y.GetReal(), this.GetImaginary() + y.GetImaginary());

        return result;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM