0

As the code below, class Foo1 implements interface IFoo, which has a property of IData.

public interface IFoo
{
    public IData Data { get; set; }
}

public interface IData { ... }

public class DataA : IData {...}
public class DataB : IData {...}

public class Foo1 : IFoo
{
    private DataB _data;
    public IData Data
    {
        get { return _data; }
        set { _data = new DataB(value); }
    }
}

If the user assigns the Data property of Foo1 with an object of DataA, and then gets the property value back later. He will get an object of DataB instead of DataA. Does this violate any OO principles? Thanks.

3
  • He will get a IData', whether it's A or B depends on what you defined as private DataB _data;` in this case, it will be DataB. Is not it?
    – Laiv
    Jan 3, 2019 at 10:16
  • @Laiv Yes, he will get DataB. Jan 3, 2019 at 10:26
  • 1
    It's ok then. you are hiding the concrete class. The only who knows its concrete class is Foo1. Any other consumers should treat _data as IData and nothing else (Ideally).
    – Laiv
    Jan 3, 2019 at 10:31

3 Answers 3

1

No, you are not violating any OO principles. Least of all because properties are not an OO concept.

There is also no rule that states that you must be able to retrieve from a property exactly the value that you stored in it.

Without better names or more documentation, you might be violating the "principle of least astonishment" but that is hard to tell from such a contrived example. And it is not an OO principle, but a general programming one.

1
  • I agree with "Properties are not an OO concept". But that also means, that you are not writing OO code. So in the spirit of the question, whether this construct is an accepted object-oriented construct, the answer is clearly "no, it isn't". Jan 4, 2019 at 12:36
2

Yes this may be violating OO principles. There is not enough of the design shown to say with certainty but what I see is a code smell.

A good class exposes functionality and hides state. When a property is exposed rather than a functional method using that state then take a good hard look. When exposing a naked, as it were, substantially complex data object then client manipulation code spreads like cancer among the using classes. It's becomes a real face palm situation with inheritance where the problem grows exponentially for want of encapsulation.

I'm not anti data transfer object (DTO) at all. However one should strive for design that conveys intent and also restricts usage by encapsulating DTOs in functional classes.


He will get an object of DataB instead of DataA. Does this violate any OO principles?

I get the impression that these days inheritance is somehow considered a violation of OO principles. The following is very OO:

public class B : A {  }

A myThing = new B(dataThingy);

Now myThing can behave as an A or B. This is a very good thing if it fits in a design that supports requirements.

Capital I interface, composition, and inheritance should be thought of as co-equal siblings that taken together make for flexible, expressive, and OO compliant design.


1

The line,

set { _data = new DataB(value); }

definitely violates the principle of least surprise/astonishment. It totally disregards the value passed to it and just creates a new DataB instead. So the setter serves no purpose other than to confuse the developer.

One solution to this is just to remove the setter from the interface:

public interface IFoo
{
    public IData Data { get; }
}

and likewise to not have a setter for Foo1.Data either. If the developer can't set the value via the property, don't provide the setter in the first place.

5
  • As a property setter, I enthusiastically agree. Given a method or perhaps better, a constructor the surprise turns into clear intent.
    – radarbob
    Jan 3, 2019 at 22:03
  • So it's better to replace the setter of the Data property with a separate ReadData(IData input) method, which is responsible for configuring the _data field by the input. Jan 4, 2019 at 7:29
  • 1
    @YantingChen - no; setters are just methods under the hood, you don't really gain much by having a separate method that accepts an IData again. You need to think about what you are trying to accomplish: if Foo1 can only use values of type DataB, then make the property type DataB (rather then IData), If you need to expose it as IData for other code, then accept a DataB in the constructor, remove the setter, and don't allow the user to change it - require a new instance to be created (immutability is your friend). If you have to be able to set the value, then do SetData(DataB value). Jan 4, 2019 at 7:47
  • BTW: "then make the property type DataB (rather then IData)" - this implies that you reevaluate if the IFoo interface is meaningful. Make sure that you really need it. Jan 4, 2019 at 7:51
  • ... think about what you are trying to accomplish... double dittos on @FilipMilovanović comment above. And, while a property (a getter | setter) is "just a method" its purpose is specialized - massaging a class variable as needed for the purpose of publicly exposing it (formatting a date for example). But that is not hiding state. Finally, making properties do/be "just like a method" becomes the problem per @BartvanIngenSchenau (selected) answer.
    – radarbob
    Jan 4, 2019 at 19:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.