在《嵌套(以太阳系为例)》中,我们显示了太阳、水星、地球和月球。但是所有的代码都是直接丢进文档类中,这样导致文档类比较臃肿,且逻辑关系复杂。很难想象如果将其他行星都加在进来,文档类会是什么样子?
现在是时候重构SunSys项目的时候了。什么事重构呢?重构就是在不改变代码外在行为(功能)的前提下,对代码做出修改,以改进程序内部结构。
分析文档类发现程序中存在4个实体,分别是太阳、水星、地球和月亮。依据面向对象思想,我们为太阳、水星、地球和月亮各自创建一个类,并将图片材质的生成放入各自的类中。
具体代码如下代码清单。
Sun.as
package
{
import org.papervision3d.materials.BitmapFileMaterial;
import org.papervision3d.objects.primitives.Sphere;
/**
* ...
* @author hellopv3d
*/
public class Sun extends Sphere
{
public function Sun()
{
var sunMaterial:BitmapFileMaterial = new BitmapFileMaterial("../assets/sun.jpg");
super(sunMaterial, 80, 20, 20);
}
}
}
Water.as
package
{
import org.papervision3d.materials.BitmapFileMaterial;
import org.papervision3d.objects.primitives.Sphere;
/**
* ...
* @author hellopv3d
*/
public class Water extends Sphere
{
public function Water()
{
var waterMaterial:BitmapFileMaterial = new BitmapFileMaterial("../assets/water.jpg");
super(waterMaterial, 30, 20, 20);
this.x = 600;
}
}
}
Earth.as
package
{
import org.papervision3d.materials.BitmapFileMaterial;
import org.papervision3d.objects.primitives.Sphere;
/**
* ...
* @author hellopv3d
*/
public class Earth extends Sphere
{
public function Earth()
{
var earthMaterial:BitmapFileMaterial = new BitmapFileMaterial("../assets/earth.jpg");
super(earthMaterial, 40, 20, 20);
this.x = 1200;
}
}
}
Moon.as
package
{
import org.papervision3d.materials.BitmapFileMaterial;
import org.papervision3d.objects.primitives.Sphere;
/**
* ...
* @author hellopv3d
*/
public class Moon extends Sphere
{
public function Moon()
{
var moonMaterial:BitmapFileMaterial = new BitmapFileMaterial("../assets/moon.jpg");
super(moonMaterial, 20, 20, 20);
this.x = 200;
}
}
}
SunSys.as
package
{
import flash.events.Event;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Sphere;
import org.papervision3d.view.BasicView;
/**
* ...
* @author yl
*/
public class SunSys extends BasicView
{
private var sun:Sphere;
private var water:Sphere;
private var earth:Sphere;
private var moon:Sphere;
private var waterContain:DisplayObject3D;
private var earthContain:DisplayObject3D;
private var moonContain:DisplayObject3D;
public function SunSys()
{
initContain();//初始化容器
init3DObjects();//初始化3D对象
//设置摄像机位置
camera.y = 500;
camera.z = -2000;
startRendering();
}
private function initContain():void {
//创建容器
waterContain = new DisplayObject3D();
scene.addChild(waterContain);
earthContain = new DisplayObject3D();
scene.addChild(earthContain);
moonContain = new DisplayObject3D();
earthContain.addChild(moonContain);
}
private function init3DObjects():void {
createSun();
createWater();
createEarth();
createMoon();
}
private function createSun():void {
//创建太阳
sun = new Sun();
scene.addChild(sun);
}
private function createWater():void {
//创建水星
water = new Water();
waterContain.addChild(water);
}
private function createEarth():void {
//创建地球
earth = new Earth();
earthContain.addChild(earth);
}
private function createMoon():void {
//创建月球
moon = new Moon();
//调用createEarth方法后才能调用此方法,因为此方法使用到earth对象
moonContain.position = earth.position;
moonContain.addChild(moon);
}
override protected function onRenderTick(e:Event = null):void {
super.onRenderTick();
//旋转各球体
earthContain.rotationY++;
waterContain.rotationY += 2;
earth.localRotationY += 3;
moonContain.rotationY += 15;
}
}
}
下图为嵌套图,红色为一个部分(earthContain),其包含earth、moonContain、moon;蓝色为一个部分(waterContain),其包含water。
重构后的类图如下所示。
Sun、Water、Earth和Moon继承自Sphere。SunSys和Sun、Water、Earth、Moon、WaterContain、EarthContain、MoonContain为组合关系。
如何判断类之间的组合关系呢?这里有一些简单的判断准则:
1 被组合的类在整体类中被定义。如在SusSys类中定义了属性sun。
2 整体类的构造函数中包含了被组合类的实例化。在我们的代码中,SunSys是文档类(整体类),测试的时候会被自动new,且首先执行构造方法,在SusSys构造方法中实例化了Sun等所有被组合类。这些类紧密的耦合在一起,同生共灭。Sun等组合类是不可以脱离SunSys而独立存在的。