多态和switch

duwa789 2009-09-11 09:55:17
在重构的方法中,多有提到利用多态性来替换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;
}
}
...全文
824 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
gjlping 2009-09-12
  • 打赏
  • 举报
回复
既然实现了同一个借口 那么就用传值时使用接口就可以了 直接调用接口的方法能达到你要的效果
wxm3630478 2009-09-11
  • 打赏
  • 举报
回复
你写的这个不用switch if else 判断呀, 只要把 子类的实例给基类, 这个基类对象就会调用相应子类中的PayAmt() 方法

反射得到类名 XXX.GetType().Name;
jishengzu 2009-09-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();
}
caixian 2009-09-11
  • 打赏
  • 举报
回复
大家都是高手,自己值得学习
jishengzu 2009-09-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(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();
}
Ricercar 2009-09-11
  • 打赏
  • 举报
回复
一般用所谓的“依赖注入”,写到一个配置文件中,这样代码就不用改了
feiyun0112 2009-09-11
  • 打赏
  • 举报
回复
你在config定义几项,比如
name=type1,value="当前命名空间名称.Engineer"
name=type2,value="当前命名空间名称.Sales"

//使用时
employee = (IEmployee)Assembly.GetExecutingAssembly().CreateInstance(ConfigurationManager.AppSettings["type"+this.type.ToString()]);
duwa789 2009-09-11
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 lin364653705 的回复:]
可以用反射,来根据条件找到需要实例化的类
具体做法
1.引入 using Systems.Reflection;  //引用名字空间
2,IEmployee result=(IEmployee)Assembly.load("当前程序集名称").CreateInstance("当前命名空间名称.Salesman(/Manager/Engineer )") 
原理就是这样,实际上后面只是一个组合好的字符串(当前命名空间名称.Salesman),根据你的type,你将字符串组合好就OK,就可得到你想new的类


[/Quote]

(可能我跳进一个坑里去了……)

所以我还是需要根据一个switch or if else来告诉反射需要获得的类名……
duwa789 2009-09-11
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 bfcady 的回复:]
C# code
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();的返回值输出来看一下就清楚了。
[/Quote]

是的。

假如情景是这样:
用户控件UC有一个属性Type,他被放到一个页面P,P中UC.Type=1.
我应该不能在UC的main中去写出new所有的employee吧。
lin364653705 2009-09-11
  • 打赏
  • 举报
回复
可以用反射,来根据条件找到需要实例化的类
具体做法
1.引入 using Systems.Reflection; //引用名字空间
2,IEmployee result=(IEmployee)Assembly.load("当前程序集名称").CreateInstance("当前命名空间名称.Salesman(/Manager/Engineer )")
原理就是这样,实际上后面只是一个组合好的字符串(当前命名空间名称.Salesman),根据你的type,你将字符串组合好就OK,就可得到你想new的类

bfcady 2009-09-11
  • 打赏
  • 举报
回复
如果你一定要保留type,那也只能是用switch了
bfcady 2009-09-11
  • 打赏
  • 举报
回复

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();的返回值输出来看一下就清楚了。
duwa789 2009-09-11
  • 打赏
  • 举报
回复

employee = (IEmployee)Assembly.GetExecutingAssembly().CreateInstance("ConsoleApplication1.Engineer");



Employee e = new Employee(new Engineer());


可能我太偏激了(面向对象基础太差),我的问题是该如何根据type让main()知道它是该new一个Engineer还是Salesman,或者是其他……

bfcady 2009-09-11
  • 打赏
  • 举报
回复
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();
feiyun0112 2009-09-11
  • 打赏
  • 举报
回复
employee = (IEmployee)Assembly.GetExecutingAssembly().CreateInstance("ConsoleApplication1.Engineer");

类名可以存到config文件

*****************************************************************************
欢迎使用CSDN论坛专用阅读器 : CSDN Reader(附全部源代码)

http://feiyun0112.cnblogs.com/
redleafe 2009-09-11
  • 打赏
  • 举报
回复
帮顶,学习了。
hgg2002 2009-09-11
  • 打赏
  • 举报
回复
楼主误解了,实际上楼主的意思是那么多的子类,楼主假想了一种情况就是,根据某个类型(type)来生成具体的类。其实这个根本用不着,我们只需要有基类的指针即可。实际应用时,这个类型(就是具体的子类)其实是能知道的。比如说,我们上面的雇员类,实际中每个雇员的类型是确定的,实例化的时候已经是根据类型选择了具体的子类了。需要调用PayAmt时,通过基类的一个引用就可以了。
zhnzzy 2009-09-11
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 sp1234 的回复:]
在Main过程中你去问如何实例化IEmployee的具体类型,好装入一个报价单的Employees集合里,这完全是你设计出来报检单对象之后的事情,是“眼前编写一个客户软件”的事情,只是使用结果,而不是真正需要你面向对象设计的场景。
[/Quote]
是的,这是在使用结果,而不是你设计的时候的具体类
LutzMark 2009-09-11
  • 打赏
  • 举报
回复
UP
duwa789 2009-09-11
  • 打赏
  • 举报
回复
对外部用户来讲,它只看得到这个应该放到工具箱里用户控件的一个Type属性,引用UC的时候需要设置一个Type值以便决定用户控件最终能输出什么。

我问道如何实例化IEmployee的具体类型,这确实也是需要在这个UC内部需要的。

但bfcady的回复中说可以暴露一个IEmployee给外部,以便在引用的时候根据应用场景直接实例化。可这样需要将接口和实现接口的类声明为public。

假如这里不愿意这么做(声明为public),我能想到的也就是我上面所问的问题了。如何根据type实例化具体类型。

==================================================================
我想我的原意是想请教怎么把switch弄掉。 而在面向对象思想上,我又混淆了概念。

我想再请问,我所设定的这个场景中,面向对象设计是如何体现的,type的那部分(反射或者暴露的IEmployee)和UC的最终输出又该怎么去理解他在面向对象设计中的位置(作用)?

我的初衷,
1. 面向对象设计体现在接口的定义和实现接口的类。
2. type部分利用配置文件的值和反射得到具体一个实例化的对象(该算是面向对象之后的应用吧)。
加载更多回复(7)

110,538

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧