在重构的方法中,多有提到利用多态性来替换switch/if else,并常常给出类似如下的代码。class Employee
{
    double payAmt(int type)
    {
        double amt = 0;
        switch (type)
        { 
            case 1:
                amt = 1;
                break;
            case 2:
                amt = 2;
                break;
            default:
                break;
        }
        return amt;
    }
}
我试着做了如下改变, 并把问题写在注释里。
class Employee
{
    int type;
    public Employee(int type)
    {
        this.type = type;
    }    void main()
    {
        IEmployee employee;
        //type该如何使用
        //这里是不是还需要条件语句来做判断……
        //或者这里如何达到如上switch的作用,根据type判断是该new一个什么类
        employee = new Engineer();
        employee.PayAmt();
    }
}
interface IEmployee
{
    double PayAmt();
}
class Engineer : IEmployee
{
    public double PayAmt()
    {
        return 3000;
    }
}
class Salesman : IEmployee
{
    public double PayAmt()
    {
        return 5000;
    }
}
class Manager : IEmployee
{
    public double PayAmt()
    {
        return 10000;
    }
}

解决方案 »

  1.   

    employee = (IEmployee)Assembly.GetExecutingAssembly().CreateInstance("ConsoleApplication1.Engineer");类名可以存到config文件
      
    *****************************************************************************
    欢迎使用CSDN论坛专用阅读器 : CSDN Reader(附全部源代码) http://feiyun0112.cnblogs.com/
      

  2.   

    public class Employee
    {
        IEmployee employee;
        public Employee(IEmployee employee)
        {
            this.employee = employee;
        }    public void main()
        {
            employee.PayAmt();
        }
    }
    public interface IEmployee
    {
        double PayAmt();
    }
    public class Engineer : IEmployee
    {
        public double PayAmt()
        {
            return 3000;
        }
    }
    public class Salesman : IEmployee
    {
        public double PayAmt()
        {
            return 5000;
        }
    }
    public class Manager : IEmployee
    {
        public double PayAmt()
        {
            return 10000;
        }
    }
    你看看这是不是你想要的吧。
    调用的时候可以这样用:Employee e = new Employee(new Engineer());
            e.main();
      

  3.   


    employee = (IEmployee)Assembly.GetExecutingAssembly().CreateInstance("ConsoleApplication1.Engineer"); Employee e = new Employee(new Engineer());
    可能我太偏激了(面向对象基础太差),我的问题是该如何根据type让main()知道它是该new一个Engineer还是Salesman,或者是其他……
      

  4.   


    Employee e = new Employee(new Engineer());
    Employee e = new Employee(new Salesman());
    Employee e = new Employee(new Manager());你用这3种方式创建对象,当你调用main方法的时候,就会调用相应具体类(Engineer、Salesman或Manager)的PayAmt方法了。你试一下就知道了,在main方法里把employee.PayAmt();的返回值输出来看一下就清楚了。
      

  5.   

    如果你一定要保留type,那也只能是用switch了
      

  6.   

    可以用反射,来根据条件找到需要实例化的类
    具体做法
    1.引入 using Systems.Reflection;  //引用名字空间
    2,IEmployee result=(IEmployee)Assembly.load("当前程序集名称").CreateInstance("当前命名空间名称.Salesman(/Manager/Engineer )")  
    原理就是这样,实际上后面只是一个组合好的字符串(当前命名空间名称.Salesman),根据你的type,你将字符串组合好就OK,就可得到你想new的类
      

  7.   


    是的。假如情景是这样:
    用户控件UC有一个属性Type,他被放到一个页面P,P中UC.Type=1.
    我应该不能在UC的main中去写出new所有的employee吧。
      

  8.   


    (可能我跳进一个坑里去了……)所以我还是需要根据一个switch or if else来告诉反射需要获得的类名……
      

  9.   

    你在config定义几项,比如
    name=type1,value="当前命名空间名称.Engineer"
    name=type2,value="当前命名空间名称.Sales"//使用时
    employee = (IEmployee)Assembly.GetExecutingAssembly().CreateInstance(ConfigurationManager.AppSettings["type"+this.type.ToString()]); 
      

  10.   

      interface IEmployee
            {
                double PayAmt();
            }
            class Engineer : IEmployee
            {
                public double PayAmt()
                {
                    return 3000;
                }
            }
            class Salesman : IEmployee
            {
                public double PayAmt()
                {
                    return 5000;
                }
            }
            class Manager : IEmployee
            {
                public double PayAmt()
                {
                    return 10000;
                }
            }        class Employee
            {
                //int type;
                public IEmployee iEmployee = null;
                public Employee(IEmployee iEmployee)
                {
                    this.iEmployee = iEmployee;
                }
            }        private void button1_Click(object sender, EventArgs e)
            {
                double value1 = new Employee(new Engineer()).iEmployee.PayAmt();
                double value2 = new Employee(new Salesman()).iEmployee.PayAmt();
                double value3 = new Employee(new Manager()).iEmployee.PayAmt();
            }
      

  11.   

    interface IEmployee
            {
                double PayAmt();
            }
            class Engineer : IEmployee
            {
                public double PayAmt()
                {
                    return 3000;
                }
            }
            class Salesman : IEmployee
            {
                public double PayAmt()
                {
                    return 5000;
                }
            }
            class Manager : IEmployee
            {
                public double PayAmt()
                {
                    return 10000;
                }
            }        class Employee
            {
                //int type;
                public IEmployee iEmployee = null;
                public Employee(int type)
                {
                    switch (type)
                    {
                        case 1:
                            iEmployee = new Engineer();
                            break;
                        case 2:
                            iEmployee = new Salesman();
                            break;
                        case 3:
                            iEmployee = new Manager();
                            break;
                        default:
                            break;
                    }
                    //this.iEmployee = iEmployee;
                }
            }        private void button1_Click(object sender, EventArgs e)
            {
                double value1 = new Employee(1).iEmployee.PayAmt();
                double value2 = new Employee(2).iEmployee.PayAmt();
                double value3 = new Employee(3).iEmployee.PayAmt();
            }
      

  12.   

    你写的这个不用switch if  else 判断呀, 只要把 子类的实例给基类, 这个基类对象就会调用相应子类中的PayAmt() 方法反射得到类名  XXX.GetType().Name;
      

  13.   


    有2种方法吧。
    1、为控件定义一个公开的属性
        IEmployee _emp;
        public IEmployee Emp
        {
            get { return _emp; }
            set { _emp = value; }
        }
    在page里面,你可以用UC.Emp = new Employee(new Engineer());来传递真正的实例2、依然保留Type
    在页面依然可以用UC.Type=1,而你在main方法里根据Type的值来决定实例化哪个具体类
    至于根据Type怎么实例化具体类,最简单的用switch,但具体类多了也不好。
    如果希望方便的话,可以用反射,加上配置文件,如下:
    (IEmployee)System.Reflection.Assembly.Load("程序集名称").CreateInstance("具体类的完整名,包括命名空间");
      

  14.   

    以上有一句话写错了在page里面,你可以用UC.Emp = new Employee(new Engineer());来传递真正的实例 要改成在page里面,你可以用UC.Emp = new Engineer();来传递真正的实例 
      

  15.   


    你错误地假设了应用场景,所以误导了之下许多人都去按照你的错误场景去“解决”,甚至去想到了“反射”?!我们开发一个通用的处理过程,可以处理通用的凡是实现IEmployee的对象,是要把这个过程放到一个“工具箱”里。然后当什么时候有个客户需要这个功能的时候,拿出来就用就好了。就好像一把螺丝起子可以拧很多种螺丝一样。而你给出的场景是在“Main()”这个作为发起操作的最终客户中,想去规定什么业务逻辑吗?有什么意义?为谁进行抽象?面向对象设计的场景是:你需要设计一个专门产品报价单对象,它包括多个产品项目,每一个产品就是一个IEmployee,于是这个报价单对象可以输出总金额:foreach(emp in this.Employees)
      sum += emp.PayAmt();而产品有很多种,在你设计这个报价单对象(类)的时候根本不知道将来会多少新的Employee种类。
    你看,你在开发的时候根本不在乎被设计处理的对象的具体子类有多少,只要抽象到同样的类型(接口)就可以,这样才体现你是基于抽象来设计的。
    而你的那种责问“Main中如何去匹配type变量的值”的初衷,不适合考虑抽象化。只是知道需要去为眼前编写一个试用软件,而不是去设计一个长期使用的通用工具。
      

  16.   

    foreach(IEmployee emp in this.Employees) 
      sum += emp.PayAmt(); 少写了类型声明。
      

  17.   

    在Main过程中你去问如何实例化IEmployee的具体类型,好装入一个报价单的Employees集合里,这完全是你设计出来报检单对象之后的事情,是“眼前编写一个客户软件”的事情,只是使用结果,而不是真正需要你面向对象设计的场景。
      

  18.   

    对外部用户来讲,它只看得到这个应该放到工具箱里用户控件的一个Type属性,引用UC的时候需要设置一个Type值以便决定用户控件最终能输出什么。我问道如何实例化IEmployee的具体类型,这确实也是需要在这个UC内部需要的。但bfcady的回复中说可以暴露一个IEmployee给外部,以便在引用的时候根据应用场景直接实例化。可这样需要将接口和实现接口的类声明为public。假如这里不愿意这么做(声明为public),我能想到的也就是我上面所问的问题了。如何根据type实例化具体类型。==================================================================
    我想我的原意是想请教怎么把switch弄掉。 而在面向对象思想上,我又混淆了概念。我想再请问,我所设定的这个场景中,面向对象设计是如何体现的,type的那部分(反射或者暴露的IEmployee)和UC的最终输出又该怎么去理解他在面向对象设计中的位置(作用)?我的初衷,
    1. 面向对象设计体现在接口的定义和实现接口的类。
    2. type部分利用配置文件的值和反射得到具体一个实例化的对象(该算是面向对象之后的应用吧)。
      

  19.   

        楼主误解了,实际上楼主的意思是那么多的子类,楼主假想了一种情况就是,根据某个类型(type)来生成具体的类。其实这个根本用不着,我们只需要有基类的指针即可。实际应用时,这个类型(就是具体的子类)其实是能知道的。比如说,我们上面的雇员类,实际中每个雇员的类型是确定的,实例化的时候已经是根据类型选择了具体的子类了。需要调用PayAmt时,通过基类的一个引用就可以了。