tags:

views:

124

answers:

3

I often have a situation like this when creating simple data objects. I have a property called Label that should have a default based on the Name of the object. So if no label is set then the Name is used otherwise use the set Label. A simple example in C#

public class FooBat {
    public string Name { get; set; }
    public string Label {
        get {
            if (_label == null) return Name;
            return _label;
        }
        set { _label = value; }
    }
}

Now the problem is if you want to edit this object you can't just bind to the Label property or you will get the default value and it will look as if there is a value there when there really isn't. So what I end up doing is create another, read-only property that does the defaulting and I use that is all instances except for when the base object is being edited. This leads to many extra properties with weird names like LabelWithDefault. Another alternative I've tried is to make Label handle the defaulting and make a new property called RealLabel that is used for editing the base object. This is just as bad.

I've thought of moving the defaulting code somewhere else but I haven't found a good place for it in any "normal" model that does not replicate the defaulting code many times.

What I have started to do now is initialize the Label field when the Name field is set (and the Label field is not) and then treat the Label field as a normal field. This works but now the code for defaulting is tied to the wrong property. Why should the Name know that the Label field cares about it? So this is also not "right."

Does anyone have any better ways of handling this problem?


I think there is a little confusion about what I'm asking for. Basically I need two different views to the same object for two different uses. In the first is the editing of the object itself where I want unset fields to show as empty (unset). The second is for all other cases (including when the object is the value of a field of another object) where I want to show each field with its dynamically determined default. Just setting the default the first time doesn't no help because if the (in this case) Name field changes then the Label field must also change until the Label field is set.


The answers are getting closer but I still think that they are too targeted to the example I gave. I was trying to give a concrete example for expository purposes but in reality this is more of a best-practices issue. The example I gave was C# and for a string property but I have the same problem with most languages and systems that I use that have frameworks where the data access and data display are handled for you as well as for data types other than strings. Changing the object that is queried from the data source is possible but often tricky and knowing when to make the change (use a sublclass in this case but not in that one) is particularly difficult.

+1  A: 
public class FooBat {
    public string Name { get; set; }    
    public string Label {
        get {
             if (_label == null) 
                 _label = Name;
             return _label;        
            }        
        set { _label = value; }    
   }
}


Regarding your update: You could subclass your object. The base-class would return null if the field has not been set and the sub-class would return your default value. Thus if you need to query if a value has been set, you would cast to the base-class.

Manu
this is just a variation of what I'm doing but you lose the information that the Label field has not been set.
James Keesey
Subclassing would help but one of the problems is that frameworks usually handle getting values from a data source and interjecting yourself to change which object is created at which time can be problamatic.
James Keesey
A: 

Deleted previous answers/updates for brevity.


Update 2: I would have to say the best way is to track whether the property has been set or not with an IsPropertySet bool. The Getter for the property would check that value to see if it should be returning its own value or the default value. And the setter for the property would set the IsPropertySet according to the set value (true if the value is not null, false if it is). The code that is using the class could then look at the IsPropertySet value to determine if it is receiving a set value or the default when it calls the Property's Getter.

public class FooBat {
   public string Name { get; set; }
   public bool IsLabelSet { get; set; }
   public string Label {
      get {
         if (IsLabelSet)
            return _label;
         else
            return Name;
      }
      set {
         IsLabelSet = value != null;
         _label = value;
      }
   }
}
Zemm
Both of these are just variations of what I'm doing. The problem is that when this is displayed to the user for editing the Label field will appear with a setting even though it has not been set--it is just defaulting.
James Keesey
Update in response to your changes.
Zemm
The only problem with that is that most frameworks use the "normal" accessor (property in C#, getter/setter in Java) so using a different type of accessor is not compatible with the framework.
James Keesey
Updated again. This will allow for normal accessor functionality and provide the ability for some additional checks to be made by the code using this class to tell where the value it gets from FooBat.Label is coming from.
Zemm
A: 

I use a Nameable interface a lot (with getName()). Before I start, I'll suggest that you don't want to do this at all. It should be the domain of your display logic, not your domain objects. Usually it's the code consuming the FooBat that is able to make this decision in a better way than the object itself. That aside...

public interface Label{
    string getLabel();
    boolean isDefault(); //or isValued() or use instanceof expressions
}

public interface Nameable{
    string getName();
}

public class FooBat implements Nameable {
    public string Name { get; set; }
    public Label Label {
        get {
            if (_label == null) {
                _label = new DefaultLabel(this);
            }
            return _label;
        }
        set { _label = value; }
    }
}

public class DefaultLabel implements Label{
    public DefaultCharSequence(Nameable named){
        this.named = named;
    }

    public string getLabel(){
        return named.getName();
    }

    public boolean isDefault(){ return true; }
 }

 public class StringLabel implements Label {
     ...
 }

It all essentially boils down to returning a better class for your label object.

Stephen
The problem I see with the code is that the DefaultCharSequence just returns the string it was created with. There is no dynamic defaulting at work. Also I was using string and Label as an example but I have this problem with non-strings as well.
James Keesey