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

C# 将两个非常相似的类重构为一个,c#,refactoring,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 newVal

这是第一节课:

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);
    }
}
公共类TextBoxInt:TextBox
{
公共int min;
公共整数最大值;
公共价值;
公共虚拟无效更新(对象发送方,事件参数e)
{
int新值;
if(int.TryParse(Text,out newValue))
{
如果(新值<最小值| |新值>最大值)
{
//做事
}
value.Set(newValue);
Text=value.Get().ToString();
}
其他的
{
Text=value.Get().ToString();
焦点();
}
}
公共文本框int(值、最小值、最大值)
{
这个值=值;
this.min=min;
this.max=max;
Text=value.Get().ToString();
LostFocus+=新事件处理程序(更新);
}
}
这是第二节课:

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);
    }
}
公共类TextBoxFloat:TextBox
{
公众持股;
公共浮动最大值;
公共价值;
公共虚拟无效更新(对象发送方,事件参数e)
{
浮动新值;
if(float.TryParse(Text,out newValue))
{
如果(新值<最小值| |新值>最大值)
{
//做事
}
value.Set(newValue);
Text=value.Get().ToString();
}
其他的
{
Text=value.Get().ToString();
焦点();
}
}
public TextBoxFloat(值、浮点最小值、浮点最大值)
{
这个值=值;
this.min=min;
this.max=max;
Text=value.Get().ToString();
LostFocus+=新事件处理程序(更新);
}
}
此外,这是值类:

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);
    }
}
公共类值
{
私人T值;
私有列表侦听器=新列表();
公共价值(T值)
{
这个值=值;
}
公共部门得不到
{
返回值;
}
公共作废集(T值)
{
这个值=值;
foreach(侦听器中的IValueListener侦听器)
{
listener.ValueUpdated(this);
}
}
公共void AddListener(IValueListener listener)
{
添加(侦听器);
}
公共void RemovelListener(IValueListener侦听器)
{
删除(侦听器);
}
}
如您所见,前两个类基本上是同一个类。唯一的区别是类型。第一个是
int
,另一个是
float
。如果我能将这两个类合并到一个类中,我似乎会得到更好的代码

我可以将
min
max
设置为浮动,如果是int类,则在需要时将它们转换为
int
。当类型为int时,我只需确保传递“整”浮点

有没有办法不用复制
Update()
方法(
如果int做codeForInt,否则如果float做sameCodeButForFloat
)就可以做到这一点

而且,即使我复制了代码,我也会遇到
value.Set(newValue)的问题-在一种情况下,
newValue
将是
int
,在另一种情况下它将是
float
,我也不能转换为
t

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


我应该把它们作为两个类,还是有办法将它们统一起来?

您可以创建一个泛型类,而不是创建单独的类

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

让一个抽象的
TextBox
类继承
TextBox
类,其中
TextBox
有一个新的
抽象字符串GetValue()
方法,怎么样?您将使用
TextBoxFloat
类实现
GetValue()
,该类将执行
float
特定逻辑,类似地,
TextBoxInt
类也将执行该逻辑。您的
文本框将类似

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();
}
公共抽象类TextBox:TextBox
{
公共卫生部;
公共T最大值;
公共价值;
公共虚拟无效更新(对象发送方,事件参数e)
{
Text=GetValue();
焦点();
}
公共TextBoxFloat(值、最小值、最大值)
{
这个值=值;
this.min=min;
this.max=max;
Text=value.Get().ToString();
LostFocus+=新事件处理程序(更新);
}
公共抽象字符串GetValue();
}

正如@flkes所说,泛型类是实现这一点的方法。你可以尝试以下方法:(你可以找到一个很好的例子)

公共抽象类TextBoxBase
{
公共抽象对象GetMin();
公共抽象对象GetMax();
公共抽象对象GetValue();
}
公共抽象类TextBox:TextBoxBase
{
公共T min{get;set;}
公共T max{get;set;}
公共T值{get;set;}
公共虚拟void SetTextBox(T mn、T mx、T val)
{
min=mn;
max=mx;
值=val;
}
公共重写对象GetMin(){return min;}
公共重写对象GetMax(){return max;}
公共重写对象GetValue(){return value;}
}
公共类TextBoxInt:TextBox
{
公共覆盖void SetTextBox(int mn、int mx、int val)
{
min=mn;
max=mx;
值=val;
}
}
公共类TextBoxFloat:TextBox
{
公共覆盖void SetTextBox(浮点mn、浮点mx、浮点val)
{
min=mn;
max=mx;
值=val;
}
}

您可能会在不知道存在的问题上取得更大的成功。这仍然给我留下了
int.TryParse(Text,out newValue)
的问题。如果我使用一个大的If并分别处理int和float,我a)使用的代码是我想要的两倍b)我无法使用value.set(newValue),因为newValue将是int或float,而不是泛型类型。
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();
}
    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;
        }
    }