Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to encapsulate a property in a base class?

My scenario is about developing Math Problems. As a IProblem interface, I thought that the two main properties that it should contain are QuestionText and Response. QuestionText always will be a string, but Response sometimes can be a complex object (a custom Fraction struc) or another datatype like string, decimal, int, etc.

    public interface IProblem
    {
        string QuestionText { get; set; }
        object Response { get; }

        bool IsComplete();
        bool IsCorrect();
    }

As you can see, Response is object. I guessed this datatype because all problems by nature have a response. And as it's an object, I define only get for future errors (casting problems).

My idea is later, in a concrete class to access to this property (Response), without the necessity to cast. Check it out?

    public abstract class Problem : IProblem
    {
        public string QuestionText { get; set;}
        public object Response { get; protected set; } 
        public virtual bool IsComplete()
        {
            return true;
        }
        public abstract bool IsCorrect();
    }

    public class BinaryProblem : Problem
    {
        public decimal N1 { get; set; }
        public decimal N2 { get; set; }
        public decimal Response
        {
            get { return (decimal)base.Response; }
            set { base.Response = value; }
        }

        public override bool IsCorrect()
        {
            return N1 + N2 == Response;
        }
    }

And here I'm testing the value.

    static void Main(string[] args)
    {
        BinaryProblem p = new BinaryProblem();
        p.N1 = 2;
        p.N2 = 4;

        p.Response = 6;

        IProblem p2 = p;
        Console.WriteLine(p2.Response);
        Console.WriteLine(p2.IsComplete().ToString());
    }

Until now, it works, but I want to know if what I'm doing is correct or a good practice. I've seen another people use new operator to do this. Others don't use the word base.

Is this a good way? Can it be causing future errors? Please, give me a feedback about my design.

EDIT: It's really necessary to access to the Response in a non-generic interface.

like image 374
Darf Zon Avatar asked Apr 19 '12 21:04

Darf Zon


People also ask

What is property encapsulation?

Encapsulation means protect important data inside the class which we do not want to be exposed outside the class. Encapsulation process means binding the data members (variable, properties) and member function (Methods) in a single unit.

How do you override a property?

An overriding property declaration must specify exactly the same access modifier, type, and name as the inherited property. Beginning with C# 9.0, read-only overriding properties support covariant return types. The overridden property must be virtual , abstract , or override .

How do properties help provide encapsulation?

Properties allow clients to access class state as if they were accessing member fields directly, while actually implementing that access through a class method. This is ideal. The client wants direct access to the state of the object and does not want to work with methods.

Can base class access derived class properties?

// As base-class pointer cannot access the derived class variable.


1 Answers

Maybe you're looking for something like this? Note, I left some things out because they weren't important to the generic solution part of the problem (like QuestionText). I also left out the base class because it appeared to be nothing more than a pass-through, and an extra, unnecessary layer. This may not be exactly what you're looking for, but I hope it helps get you there.

First, this is how everything is used:
Edit: Notice how they can all be treated as the non-generic IProblem now.

private static void StackOverflowQuestion()
{
    IProblem<int> problem1 = new IntProblem(2, 4);
    problem1.Response = 6;

    IProblem<decimal> problem2 = new DecimalProblem(5, 10);
    problem2.Response = .5M;

    Console.WriteLine("Problem 1 is correct: {0}", problem1.IsCorrect());
    Console.WriteLine("Problem 2 is correct: {0}", problem2.IsCorrect());

    List<IProblem> problems = new List<IProblem>();
    problems.Add(problem1);
    problems.Add(problem2);
    problems.ForEach(problem => Debug.WriteLine(problem.GetResponse()));
}

Edit: Here's the non-generic interface so many problems can be used in a list and treated the same way:

public interface IProblem
{
    object GetResponse();
}

Here's the interface:
Edit: Notice that this now implements the non-generic interface.

public interface IProblem<T> : IProblem
{
    T Response { get; set; }
    bool IsCorrect();
}

And here are the classes:
Edit: Notice the new GetResponse() methods.

public class IntProblem : IProblem<int>
{
    private int _number1 { get; set; }
    private int _number2 { get; set; }

    public int Response { get; set; }

    public IntProblem(int number1, int number2)
    {
        this._number1 = number1;
        this._number2 = number2;
    }

    public bool IsCorrect()
    {
        return this._number1 + this._number2 == Response;
    }

    public object GetResponse()
    {
        return this.Response;
    }
}

public class DecimalProblem : IProblem<decimal>
{
    private decimal _number1 { get; set; }
    private decimal _number2 { get; set; }

    public decimal Response { get; set; }

    public DecimalProblem(decimal number1, decimal number2)
    {
        this._number1 = number1;
        this._number2 = number2;
    }

    public bool IsCorrect()
    {
        return this._number1 / this._number2 == Response;
    }

    public object GetResponse()
    {
        return this.Response;
    }
}
like image 65
Bob Horn Avatar answered Nov 06 '22 04:11

Bob Horn