建造者模式(二):游戏角色设计的建造者模式解决方案

8.3完整解决方案

      Sunny公司开发人员决定使用建造者模式来实现游戏角色的创建,其基本结构如图8-3所示:

8-3 游戏角色创建结构图

      在图8-3中,ActorController充当指挥者ActorBuilder充当抽象建造者,HeroBuilderAngelBuilderDevilBuilder充当具体建造者,Actor充当复杂产品。完整代码如下所示:

指挥者类ActorController定义了construct()方法,该方法拥有一个抽象建造者ActorBuilder类型的参数,在该方法内部实现了游戏角色对象的逐步构建,代码如下所示:

//Actor角色类:复杂产品,考虑到代码的可读性,只列出部分成员属性,且成员属性的类型均为String,真实情况下,有些成员属性的类型需自定义
class Actor
{
       private  String type; //角色类型
       private  String sex; //性别
       private  String face; //脸型
       private  String costume; //服装
       private  String hairstyle; //发型

       public  void setType(String type) {
              this.type  = type;
       }

       public  void setSex(String sex) {
              this.sex  = sex;
       }

       public  void setFace(String face) {
              this.face  = face;
       }

       public  void setCostume(String costume) {
              this.costume  = costume;
       }

       public  void setHairstyle(String hairstyle) {
              this.hairstyle  = hairstyle;
       }

       public  String getType() {
              return  (this.type);
       }

       public  String getSex() {
              return  (this.sex);
       }

       public  String getFace() {
              return  (this.face);
       }

       public  String getCostume() {
              return  (this.costume);
       }

       public  String getHairstyle() {
              return  (this.hairstyle);
       }
}

//角色建造器:抽象建造者
abstract class ActorBuilder
{
       protected  Actor actor = new Actor();
      
       public  abstract void buildType();
       public  abstract void buildSex();
       public  abstract void buildFace();
       public  abstract void buildCostume();
       public  abstract void buildHairstyle();

    //工厂方法,返回一个完整的游戏角色对象

       public Actor createActor() {
              return actor;
       }
}

//英雄角色建造器:具体建造者
class HeroBuilder extends ActorBuilder {

       public  void buildType(){
              actor.setType("英雄");
       }

       public  void buildSex(){
              actor.setSex("男");
       }

       public  void buildFace(){
              actor.setFace("英俊");
       }

       public  void buildCostume() {
              actor.setCostume("盔甲");
       }

       public  void buildHairstyle() {
              actor.setHairstyle("飘逸");
       }    
}

//天使角色建造器:具体建造者
class AngelBuilder extends ActorBuilder{

       public  void buildType() {
              actor.setType("天使");
       }

       public  void buildSex() {
              actor.setSex("女");
       }

       public  void buildFace() {
              actor.setFace("漂亮");
       }

       public  void buildCostume() {
              actor.setCostume("白裙");
       }

       public  void buildHairstyle(){
              actor.setHairstyle("披肩长发");
       }    
}

//恶魔角色建造器:具体建造者
class DevilBuilder extends ActorBuilder
{

       public  void buildType() {
              actor.setType("恶魔");
       }

       public  void buildSex()
       {
              actor.setSex("妖");
       }

       public  void buildFace()
       {
              actor.setFace("丑陋");
       }

       public  void buildCostume()
       {
              actor.setCostume("黑衣");
       }

       public  void buildHairstyle()
       {
              actor.setHairstyle("光头");
       }    
}


//游戏角色创建控制器:指挥者

class ActorController {

    //逐步构建复杂产品对象
       public Actor construct(ActorBuilder ab)   {
              Actor actor;
              ab.buildType();
              ab.buildSex();
              ab.buildFace();
              ab.buildCostume();
              ab.buildHairstyle();
              actor=ab.createActor();
              return actor;
       }
}


为了提高系统的灵活性和可扩展性,我们将具体建造者类的类名存储在配置文件中,并通过工具类XMLUtil来读取配置文件并反射生成对象,XMLUtil类的代码如下所示:


import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;

class XMLUtil{

//该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
       public  static Object getBean(){

         try {
            //创建文档对象
            DocumentBuilderFactory  dFactory = DocumentBuilderFactory.newInstance();
            <span style="font-family:Times New Roman;">D</span>ocumentBuilder  builder = dFactory.newDocumentBuilder();
            Document  doc;                                               
            doc  = builder.parse(new File("config.xml"));
           
            //获取包含类名的文本节点
            NodeList  nl = doc.getElementsByTagName("className");
            Node  classNode=nl.item(0).getFirstChild();
            String  cName=classNode.getNodeValue();
           
            //通过类名生成实例对象并将其返回
            Class c=Class.forName(cName);
            Object obj=c.newInstance();

            return obj;
         } catch(Exception e){
              e.printStackTrace();
              return null;
          }
       }
}

          配置文件config.xml中存储了具体建造者类的类名,代码如下所示:

<?xml version="1.0"?>
<config>
       <className>AngelBuilder</className>
</config>    

        编写如下客户端测试代码:

     

class Client{
       public  static void main(String args[])
       {
              ActorBuilder ab; //针对抽象建造者编程
              ab =  (ActorBuilder)XMLUtil.getBean(); //反射生成具体建造者对象
              ActorController ac = new  ActorController();
              Actor actor;
              actor = ac.construct(ab); //通过指挥者创建完整的建造者对象

              String  type = actor.getType();
              System.out.println(type  + "的外观:");
              System.out.println("性别:" + actor.getSex());
              System.out.println("面容:" + actor.getFace());
              System.out.println("服装:" + actor.getCostume());
              System.out.println("发型:" + actor.getHairstyle());
       }
}

编译并运行程序,输出结果如下:

天使的外观:

性别:女

面容:漂亮

服装:白裙

发型:披肩长发

      在建造者模式中,客户端只需实例化指挥者类,指挥者类针对抽象建造者编程,客户端根据需要传入具体的建造者类型,指挥者将指导具体建造者一步一步构造一个完整的产品(逐步调用具体建造者的buildX()方法),相同的构造过程可以创建完全不同的产品。在游戏角色实例中,如果需要更换角色,只需要修改配置文件,更换具体角色建造者类即可;如果需要增加新角色,可以增加一个新的具体角色建造者类作为抽象角色建造者的子类,再修改配置文件即可,原有代码无须修改,完全符合“开闭原则”。

【作者:刘伟 http://blog.csdn.net/lovelio】

阅读更多
个人分类: 设计模式
上一篇复杂对象的组装与创建——建造者模式(一):游戏角色设计,建造者模式概述
下一篇建造者模式(三):关于Director的进一步讨论,建造者模式总结
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭