求助帖:关于一个类似多态的问题。
vb.net吧
全部回复
仅看楼主
level 1
慢慢醒 楼主
我想设计一个程序,可以计算长方形、圆形,三角形的面积。要求,如果还有新的形状的话,直接写一个该形状的类,不用再添加其他代码,就可以增加计算这种形状的面积的功能。为了实现上述功能。我设想可以使用多态的方式来解决。基本思路是,设计一个父类“形状”,父类含有属性“面积”“描述”【这个属性是按照格式化的要求,来描述形状的类型和参数,例如:J5*4,就是矩形,长5,宽4,再例如:Or5表示半径为5的圆形,Od7则表示直径是7的园。】,方法“计算面积”,然后再写子类“三角形”“正方形”“矩形”“梯形”等等。在计算时,只要确定了形状的类型,就可以调用响应的“面积”方法来计算面积。
在这里我遇到了一个困难:
如何通过描述来确定,选用那个类型的对象来计算面积?
如果使用Select Case 对“描述”的首字母进行判断,则不利于程序的扩展。
请问各位朋友,谁知道该如何解决这个问题?
2017年01月30日 03点01分 1
level 9
这个问题用重载就行了。不用那么复杂
2017年01月30日 17点01分 4
重载的话如何判断,使用哪种形状的类来计算面积?
2017年01月31日 03点01分
level 1
慢慢醒 楼主
重载的话如何判断,使用哪种形状的类来计算面积?
2017年01月31日 02点01分 5
level 1
慢慢醒 楼主
2017年01月31日 02点01分 6
level 11
根本不用首字母。
你把父类的计算面积设成MustOverride()直接让子类重写这个计算面积就可以了。到时候调用计算面积的时候就会调用子类的方法。
2017年01月31日 04点01分 7
level 11
要是我我就这样写。
Posted From Baidu Tieba Windows 10 UWP Edition
2017年01月31日 04点01分 8
非常感谢您的答复,可能是我前面没有说清楚,请看第10楼和11楼。
2017年01月31日 07点01分
@zbx14251 我已经解决了问题,你看看14楼,这个方法是否还存在问题?
2017年01月31日 10点01分
level 9
类在初始化的时候确定形状啊,初始化就重载。
三角形 dim s3 = new myshape(1,2,2)
四边形 dim s4 = new myshape(2,2,2,2)
同理计算面积的方法也可以重载。我的意思是不要为了练习语言而故意增加难度,使用虚函数继承基类代码当然是要美观的,但是简单起见一个类通过重载就能解决的问题没必要弄好几个(如果简单的话)。当然你之前说的方法也无不可,我只是觉得稍微有点墨迹,都是个人习惯。
2017年01月31日 04点01分 9
非常感谢您的答复,可能是我前面没有说清楚,请看第10楼和11楼。
2017年01月31日 07点01分
level 1
慢慢醒 楼主
非常感谢各位,过年期间答复我。我这里说明一下我为什么要这样做。
首先介绍一下问题的背景,提出问题的软件不是计算矩形、圆形的,而是计算我所在专业的东西,为了大家好理解,我举了计算形状面积的例子。下面都以计算形状来介绍。
我的这个软件需要批量计算大量的数据,不同的形状计算方法不一样。这个程序已经有十几年的历史了,隔两年就要增加一些形状。每种形状又有几千个不同的尺寸。这些不同尺寸的形状在数据库中,使用一个符合某种规则的描述方法来表述,类似于Or5表示半径为5的圆形等。这样在软件读出这些数据后,需要根据字母O判断,用计算圆形的类来处理。同时根据字母r判断,后面的5是半径,不是直径。
我以前的版本都是用select case 语句判断 物体类型 ,不同的类型使用不同的函数或者类来计算。而select case方法需要添加新的类,还要修改select case 语句,添加选项。我觉得这样做体现不了面向对象变成的好处。和我最早用面向过程编程没有啥区别。于是突发奇想,希望找一个方法,在添加新的物体类型时,只要将新物体的类放在指定的代码段里,就可以自动添加了,不用再去修改select case 语句,这样程序的可维护性就大幅度提高了。这个就是问题的由来。
2017年01月31日 07点01分 10
level 1
慢慢醒 楼主
下来说一下软件的实现思路:
从数据库读取了一条记录后,使用函数将描述解析成不同的数据,第一部分是表示形状类型和尺寸描述方法的字母,第二部分是一个由若干个数字组成的数组。例如Or5就变成了“Or”和数字5,如果是J3*5就会变成“J”和一个值由3和5组成的数组。等等。
然后根据字母部分判断使用哪个函数来计算面积。再将面积输出到数据库中。上述过程用一个简单的代码来写就是这样:
public function CalVolum( Script as string ) as double
dim Type as string , Dimension() as double
Type=ReadType(Script) ‘从描述中读取形状的类型
Dimension=ReadDimension(Script) ‘读取形状的特性尺寸
select case Type
case "Or"
Dim P as new Yuan ‘Yuan表示圆形的 类
P.r=Dimension(0)
case "Od"
Dim P as new Yuan ‘Yuan表示圆形的 类
P.d=Dimension(0)
case "J"
...
case else
...
end select
CalVolum=P.Volum
end Function
目前的难点就在于,不使用 Select Case 语句的情况下,如果让程序选择正确的函数或者类来计算?
2017年01月31日 07点01分 11
level 7
如果是我,我会这样设计:
1.设计一个虚基类,一个计算的虚函数,描述作为构造函数的参数。
2.根据不同的形状继承实现不同的计算方法。
3.在数据库里增加一列,表示每个记录的要使用的类名称。
4.读取记录之后,只要根据类名称,用Activator实例化对应的类,调用基类的计算方法即可。
因为要选择哪个类来计算这一步是省略不了的,那么最简单的话就保存在数据库里就行。这样的好处在于,只要在数据库里标明,然后在客户端编写对应的类就行,不用写select case,用代码的可读性和可维护性来说也简单多了。
2017年01月31日 08点01分 12
非常感谢,您的思路很对。我刚刚解决了问题,请看14楼。
2017年01月31日 09点01分
level 11
楼上说的思路很对。也许过一会我在电脑旁边就可以写出来一个成品代码给您了。
2017年01月31日 09点01分 13
不过增加一列倒是没必要,把Yuan改成O……也行吧……
2017年01月31日 09点01分
level 1
慢慢醒 楼主
@sowo 您说的非常好,我刚刚解决了这个问题,使用的就是您的办法。只是我在一个大的类中添加了一系列的形状类,然后遍历了所有的形状类并添加到一个集合中,集合使用形状的名称作为key,这样可以直接用形状的名称就可以从集合中获得相应形状的类实例。
在遍历形状类的时候,使用了GetMember获得大类下的成员,用Activator获得相应类成员的实例。
由于用Activator获得类实例需要后期绑定,而我的数据量太大,后期绑定严重影响计算效率,所以我就搞了个集合,然后将这个集合作为Shared(共享成员,Java叫静态),大类初始化的时候计算一遍,后面的重复计算不再调用Activator,这样就可以提高运行速度。
这个只是我的思路未必最优,欢迎各位朋友指正。下面是部分代码:
2017年01月31日 09点01分 14
代码中的 debug.print是用来调试的,大家无视好了。
2017年01月31日 09点01分
如果是我,我会这样实现:把描述当成一个可以设置的属性,在读取每条记录的时候,如果有需要就实例化,并且保存实例,下一次需要同一个类计算的时候,直接保存的实例取出来,把描述更新计算就行了。实例太多肯定会影响效率,而且按照你的需求,根本不需要每条记录都实例化
2017年01月31日 09点01分
看了一下你的代码,为什么不用类型转换,转换成基类?完全没有必要后期绑定,毫无意义
2017年01月31日 09点01分
@sowo 你说的有道理,理论上可以把I_O变量由object改为基类。但是我试验了一下,好像出问题了。
2017年01月31日 10点01分
level 9
这个问题最好的做法写一个基类名字叫做shape,所有形状的共有属性写在这里面,用于继承。
然后对每种形状分别以一个类,三角形类,四边形类,梯形类....等等全部继承自shape,如有必要可以对基类的某些内容重写。
尽量把所有通用的属性全部写在基类里面,这样添加一个新的形状就简单,主要用类的继承提高代码的复用性。我刚看楼上大哥写的就不错。
2017年01月31日 11点01分 16
level 1
慢慢醒 楼主
十五楼呢?
2017年01月31日 12点01分 17
1 2 尾页