日期:2014-05-20  浏览次数:20928 次

类爆炸问题,对维护也是恶梦?

原意在ERP项目中有设计一个工序类用來描述工序:
public Process
{
 
 public string ProcessNo
{
 get{}
 set{}
}
public string ProcessDesc
{
 get{}
 set{}
}
//宽Size2 属性
 public virtual float GetSize2();
 public virtual void SetSize2(float _size2);

}

如下图:
----------------------------
工序号 工序名称 Size2求法 说明
----------------------------
91 包裝 F_GetPack(Productobj obj,int X) 成品尺寸宽
95 粘合 F_GetSize2(layoutobj obj) 排版尺寸的宽
2A 过油 F_GetSize(int size1,int size2) 用户输入的值得到
.......................
99 XX F_PA() ...........

但是发现实际情况下是公司有几百个不同的工序,最主要有些工序同样的属性如(宽),不同的名字或在不同的产品时会有不同的方法求得(但不是所有的都不同)。我的问题是:
  如不同的工序用继承的方法,不同的子类重写不同的方案,会产生上百个工序类,而且将来工序会因需要自动增加,显然会产生类爆炸问题,对维护也是恶梦! 
  如不用继承的方法,转而只用写成一个类中,用不同的函数名不同的方式,显多也是太多函数,且一样不能维护。

请问各位有什么好的设计类的方案?



------解决方案--------------------
你的问题主要是在计算方法上,所以把“size2求法”改成两部部分,算法名称和参数表。
另一个算法的注册管理类,用于添加、维护和调用算法。
所有的算法可以定义一个算法基类,有public float virtual Calc();
每个算法类用属性维护算法参数,orerride Calc()方法。并将算法类对象在算法注册管理类中注册。

------解决方案--------------------
使用 抽象工厂 模式 管理若干的类。

这是第一步,如果按照理论来是使用 组合 方式,使用类似策略模式来处理,把不同的处理方法封装好,然后创建类的时候动态的组合这些封装好的策略,但是这仅仅是理论。

如果你的每个类对应的工序的处理过程并不是这种原料般的组合过程那就不能用这种模式。

如果在.Net环境下我推经用Hashtable把“工序名字”和“类类型名称”组合的存入。
如果在一般环境下我推荐写一个类,这个类负责管理“工序名称”到“工序处理过程”的映射,即String和函数指针的关系。

更简单的是把函数指针们用宏写入一个初始化的数组,然后用枚举。

如果完全用OO方法,我认为这种情况下你的抽象粒度是不合理的,每个工序都抽象为类是不是有点过于细,你可以考虑以后从更高的层次抽象。如果必须这么做,也可以丰富一下抽象工厂,让抽象工厂来做更多事情,比如注册一个类型,等等操作。

嗯嗯,欢迎继续讨论!
------解决方案--------------------
给你提供一点框架的东西:
C# code

    /// <summary>
    /// 工序类
    /// </summary>
    public class Process
    {
        public string ProcessNo
        {
            get; set;
        }
        public string ProcessDesc
        {
            get; set;
        }

        public CalcMethodInfo GetMethod { get; set; }
        public CalcMethodInfo SetMethod { get; set; }

        public float Size
        {
            get
            {
                return CalcMethodManager.Instance[GetMethod.MethodName].GetSize();
            }
            set
            {
                CalcMethodManager.Instance[SetMethod.MethodName].SetSize(value);
            }
        }
    }

    /// <summary>
    /// 计算方法信息类
    /// </summary>
    public class CalcMethodInfo
    {
        public string MethodName { get; set; }
        public object[] Args { get; set; }
    }

    /// <summary>
    /// 负责计算方法注册、调用的管理类。
    /// 可以考虑用配置文件,部署运行起来方便
    /// </summary>
    public class CalcMethodManager:Dictionary<string, CalcMethodBase>
    {
        /// <summary>
        /// 注册计算方法
        /// </summary>
        /// <param name="calcMethod"></param>
        public void Register(CalcMethodBase calcMethod)
        {
            Add(calcMethod.Name, calcMethod);
        }

        public static CalcMethodManager Instance = new CalcMethodManager();

        CalcMethodManager()
        {
            //可以在此从配置文件读出方法,并登记。也可以程序中手工调用Register方法注册。
        }
    }

    /// <summary>
    /// 方法类。
    ///可以考虑配置,部署运行起来方便
    /// </summary>
    public abstract class CalcMethodBase
    {
        public string Name { get; set; }

        /// <summary>
        /// 以下2个方法在子类中必须被重写
        /// </summary>
        /// <returns></returns>
        public virtual float GetSize() { throw new NotImplementedException(); }
        public virtual void SetSize(float value) { throw new NotImplementedException(); }
    }

    /// <summary>
    /// 计算方法的一个实例类。
    /// 可以将类的Namespace,assembly信息写入配置文件,为了CalcMethodManager可以自动读取
    /// </summary>
    public class CalcMethodM1:CalcMethodBase
    {
        public int Size1 { get; set; }
        public int Size2 { get; set; }
        public override float GetSize()
        {
            //换成需要的算法
            return Size1 + Size2;
        }
        public override void SetSize(float value)
        {
            //换成需要的算法
            Size1 = (int)value/2;
            Size2 = (int)(value - Size1);
        }
    }