将两个非常相似的类重构为一个

时间:2016-09-09 13:18:46

标签: c# refactoring

这是第一堂课:

public class TextBoxInt : TextBox
{
    public int min;
    public int max;

    public Value<int> value;

    public virtual void Update(object sender, EventArgs e)
    {
        int newValue;

        if (int.TryParse(Text, out newValue))
        {
            if (newValue < min || newValue > max)
            {
                //do thing A
            }

            value.Set(newValue);
            Text = value.Get().ToString();
        }

        else
        {
            Text = value.Get().ToString();
            Focus();
        }
    }

    public TextBoxInt(Value<int> value, int min, int max)
    {
        this.value = value;
        this.min = min;
        this.max = max;

        Text = value.Get().ToString();
        LostFocus += new EventHandler(update);
    }
}

这是第二堂课:

public class TextBoxFloat : TextBox
{
    public float min;
    public float max;

    public Value<float> value;

    public virtual void Update(object sender, EventArgs e)
    {
        float newValue;

        if (float.TryParse(Text, out newValue))
        {
            if (newValue < min || newValue > max)
            {
                //do thing A
            }

            value.Set(newValue);
            Text = value.Get().ToString();
        }

        else
        {
            Text = value.Get().ToString();
            Focus();
        }
    }

    public TextBoxFloat(Value<float> value, float min, float max)
    {
        this.value = value;
        this.min = min;
        this.max = max;

        Text = value.Get().ToString();

        LostFocus += new EventHandler(update);
    }
}

此外,这是Value类:

public class Value<T>
{
    private T value;
    private List<IValueListener<T>> listeners = new List<IValueListener<T>>();

    public Value(T value)
    {
        this.value = value;
    }

    public T Get()
    {
        return value;
    }

    public void Set(T value)
    {
        this.value = value;

        foreach (IValueListener<T> listener in listeners)
        {
            listener.ValueUpdated(this);
        }
    }

    public void AddListener(IValueListener<T> listener)
    {
        listeners.Add(listener);
    }

    public void RemoveListener(IValueListener<T> listener)
    {
        listeners.Remove(listener);
    }
}

如您所见,前两个类基本上是同一个类。唯一的区别是类型。第一个是int,另一个是float。如果我可以将这两个代码组合成一个类,我似乎可以制作更好的代码。

我可以将minmax设置为浮点数,并在需要时将它们转换为int,如果它是一个int类。我只是确保在类型为int时传递“整个”浮点数。

有没有办法在不重复Update()方法(If int do codeForInt, else if float do sameCodeButForFloat)的情况下完成?

此外,即使我复制了代码,我也会遇到value.Set(newValue);的问题 - 在一种情况下newValueint,在另一种情况下会float },我无法将其转换为T

另外,有没有办法限制泛型类型?要指定它只能是int还是float?

我应该把它们留作两个类,还是有办法统一它们?

3 个答案:

答案 0 :(得分:1)

您可以创建一个通用类,而不是创建单独的类。

public class BoundedTextBox<T> : TextBox where T : IComparable<T> ...

声明T实现IComparable<T>将允许您在设置操作期间检查T是否在边界内。

if (newValue.CompareTo(min) <= 0 || newValue.CompareTo(max) >= 0)
{
    // do thing A
}

答案 1 :(得分:1)

TextBox<T>类继承一个抽象的TextBox类,其中TextBox<T>有一个新的abstract string GetValue()方法怎么样?您将TextBoxFloat类实现GetValue(),它将执行float特定逻辑,类似TextBoxInt类。您的TextBox<T>就像是

public abstract class TextBox<T> : TextBox
{
    public T min;
    public T max;

    public Value<T> value;

    public virtual void Update(object sender, EventArgs e)
    {
        Text = GetValue();
        Focus();
    }

    public TextBoxFloat(Value<T> value, T min, T max)
    {
        this.value = value;
        this.min = min;
        this.max = max;

        Text = value.Get().ToString();
        LostFocus += new EventHandler(update);
    }

    public abstract string GetValue();
}

答案 2 :(得分:0)

正如@flkes所说,通用类是继续使用这个类的方法。您可以尝试以下几点:(您可以找到一个很好的例子Here

    public abstract class TextBoxBase
    {
        public abstract object GetMin();
        public abstract object GetMax();
        public abstract object GetValue();
    }

    public abstract class TextBox<T> : TextBoxBase
    {
        public T min { get; set; }
        public T max { get; set; }
        public T value { get; set; }
        public virtual void SetTextBox(T mn, T mx, T val)
        {
            min = mn;
            max = mx;
            value = val;
        }
        public override object GetMin() { return min; }
        public override object GetMax() { return max; }
        public override object GetValue() { return value; }
    }

    public class TextBoxInt : TextBox<int>
    {
        public override void SetTextBox(int mn, int mx, int val)
        {
            min = mn;
            max = mx;
            value = val;
        }
    }

    public class TextBoxFloat : TextBox<float>
    {
        public override void SetTextBox(float mn, float mx, float val)
        {
            min = mn;
            max = mx;
            value = val;
        }
    }