在《重构太阳系(1)》中,我们将太阳、水星、地球和月球从SunSys分离出来单独成类。并了解了组合的关系。但是我们忽略了3个容器与水星、地球、月亮的关系。我们通过下图可以清楚地明白SunSys中所有类的关系。
SunSys由Sun、WaterContainer和EarthContainer三个部分构成。WaterContainer由Water构成。EarthContain由Earth、MoonContainer两个部分构成。MoonContainer由Moon构成。
依据上面的分析,继续重构SunSys项目。将WaterContainer、EarthContainer和MoonContainer编写成单独的类。
WaterContainer.as
package
{
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Sphere;
/**
* ...
* @author hellopv3d
*/
public class WaterContainer extends DisplayObject3D
{
private var water:Sphere;
public function WaterContainer()
{
water = new Water();
this.addChild(water);
}
}
}
MoonContainer.as
package
{
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Sphere;
/**
* ...
* @author hellopv3d
*/
public class MoonContainer extends DisplayObject3D
{
private var moon:Sphere;
public function MoonContainer()
{
moon = new Moon();
this.addChild(moon);
}
}
}
EarthContainer.as
package
{
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Sphere;
/**
* ...
* @author hellopv3d
*/
public class EarthContainer extends DisplayObject3D
{
private var earth:Sphere;
private var moonContainer:MoonContainer;
public function EarthContainer()
{
earth = new Earth();
this.addChild(earth);
moonContainer = new MoonContainer();
this.addChild(moonContainer);
moonContainer.position = earth.position;
}
}
}
SunSys.as
package
{
import flash.events.Event;
import mx.core.BitmapAsset;
import org.papervision3d.core.geom.Particles;
import org.papervision3d.core.geom.renderables.Particle;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.materials.special.ParticleMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Sphere;
import org.papervision3d.view.BasicView;
/**
* ...
* @author hellopv3d
*/
//[SWF(width = "1024", height = "800", backgroundColor = "0x000000")]
public class SunSys extends BasicView
{
private var sun:Sphere;
private var waterContain:WaterContainer;
private var earthContain:EarthContainer;
public function SunSys()
{
initContain();//初始化容器
init3DObjects();//初始化3D对象
//调整摄像机
camera.y = 500;
camera.z = -2000;
startRendering();
}
private function initContain():void {
waterContain = new WaterContainer();
scene.addChild(waterContain);
//创建容器
earthContain = new EarthContainer();
scene.addChild(earthContain);
}
private function init3DObjects():void {
createSun();
}
private function createSun():void {
//创建太阳
sun = new Sun();
scene.addChild(sun);
}
override protected function onRenderTick(e:Event = null):void {
super.onRenderTick();
waterContain.rotationY += 3;
earthContain.rotationY++;
}
}
}
重构后的类图如下所示。
从SunSys代码可以看到,SunSys类属性只有sun、waterContain和earthContainer。我们在文档类中只关注这三个类的实例化,Water、Earth、MoonContainer和Moon都被封装起来了,当然也没有必要去理会了。
测试运行,发现缺少了地球自转和月球绕地球转动。因为在文档类属性中没有定义Earth对象和MoonContainer对象,因此,不能在刷屏方法onRenderTick中使用。我们将earth组合进earthContainer中,隐藏了earth类。只要我们在EarthContainer类中编写获取earth对象的方法即可解决这个问题。如下代码所示。
EarthContainer.as
package
{
……
public function getEarth():Sphere {
return earth;
}
public function getMoonContainer():MoonContainer {
return moonContainer;
}
……
}
SunSys.as
package
{
……
override protected function onRenderTick(e:Event = null):void {
super.onRenderTick();
waterContain.rotationY += 3;
earthContain.rotationY++;
//earth.localRotationY += 3;
earthContain.getEarth().rotationY += 3;
//moonContain.localRotationY += 15;
earthContain.getMoonContainer().localRotationY += 15;
}
……
}
但是这样和面向对象思想冲突,将地球自己的事情(自转)交给了文档类实现。有没有什么好的办法来处理这个问题呢?有的,不过要请来哈希表。
在运用哈希表之前,我们可以进一步重构,将SunSys做成一个单独的类,而不是文档类。这样我们就可以在文档类中直接生成Sunsys实例,对于其他的类,我们就没有必要去理会了。
SunSys.as
package
{
import org.papervision3d.objects.DisplayObject3D;
/**
* ...
* @author yl
*/
public class SunSys extends DisplayObject3D
{
private var sun:Sun;
private var earthContain:EarthContainer;
private var waterContain:WaterContainer;
public function SunSys()
{
initContainer();//创建容器
init3DObjects();//创建3D物体
}
private function init3DObjects():void {
createSun();
createSpace();
}
private function createSpace():void {
//创建粒子容器,并加入场景显示
var particles:Space = new Space();
this.addChild(particles);
}
private function createSun():void {
//创建太阳
sun = new Sun();
this.addChild(sun);
}
private function initContainer():void {
//创建水星容器
waterContain = new WaterContainer();
this.addChild(waterContain);
//创建地球容器
earthContain = new EarthContainer();
this.addChild(earthContain);
}
}
}
SunSysTest.as
package
{
import flash.events.Event;
import org.papervision3d.view.BasicView;
/**
* ...
* @author yl
*/
public class SunSysTest extends BasicView
{
private var sunSys:SunSys;
public function SunSysTest()
{
sunSys = new SunSys();
scene.addChild(sunSys);
camera.z = -2000;
camera.y = 1000;
startRendering();
}
override protected function onRenderTick(e:Event = null):void {
super.onRenderTick();
}
}
}
由于文档类除了SunSys类属性外没有任何属性,因此不能在刷屏方法中进行相关的转动。
解决方法是给需要的类提供public接口,返回自身即可。具体代码可通过下面链接下载:
http://download.youkuaiyun.com/detail/gdhyyanglang/4181810