从王者荣耀看设计模式(十三.工厂方法模式)

编程入门 行业动态 更新时间:2024-10-28 04:21:28

从王者<a href=https://www.elefans.com/category/jswz/34/1767204.html style=荣耀看设计模式(十三.工厂方法模式)"/>

从王者荣耀看设计模式(十三.工厂方法模式)

从王者荣耀看设计模式(工厂方法模式)

一.简介

王者荣耀游戏设计师根据英雄技能、属性、天赋等因素,将英雄划分为射手、辅助、打野、法师、坦克、战士等职业。一局比赛存在多类英雄可供选择。玩家在挑选游戏英雄时,合理的英雄职业搭配是赢得游戏胜利的基本保证。

二.工厂方法模式

工厂方法模式(Factory Method Pattern):工厂方法模式又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。

模式动机
在简单工厂模式中,所有的产品都是由同一个工厂创建,工厂类职责较重,业务逻辑较为复杂,具体产品类与工厂类之间的耦合度高。而工厂方法模式可以很好的解决这一问题。在本实例中,声明了坦克、法师、射手等多个工厂子类,每个工厂生产相应职业的英雄。

  • 工厂方法模式使用场景
  1. 一个类不知道他所需要的对象的类:在工厂方法模式中,客户端不需要知道
    具体产品类的类名,只需知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
  2. 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需提供一个创建产品的接口,而由其子类来确定具体要求创建的对象,利用面向对象的多态性和里氏替换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展
  3. 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中
  • 工厂方法模式涉及的设计原则有:
    ★依赖于抽象,不依赖于具体类
    ★对于扩展是开放的,对于修改是封闭的
    ★封装变化
    ★针对接口编程,不针对实现编程

  • 工厂方法模式的通用类图:

  • 工厂方法模式涉及的角色有:
    Product(抽象产品)
    抽象产品是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的共同父类或接口
    ConcreteProduct(具体产品)
    具体产品实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,它们之间一一对应。
    Factory(抽象工厂)
    在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个产品。抽象工厂是工厂方法模式的核心,它与应用程序无关。任何在模式中创建对象的工厂类都必须实现该接口
    ConcreteFactory(具体工厂)
    具体工厂是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户调用,返回一个具体产品类的实例。在具体工厂类中包含了与应用程序紧密相关的逻辑,并且接受应用程序调用以创建产品对象。

  • 工厂方法模式的优点:

  1. 在工厂方法模式中,工厂方法模式用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将其实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无需知道具体产品类的类名。
  2. 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。他能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类
  3. 使用工厂方法模式的另一优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他具体工厂和具体类,而只要添加一个具体工厂和具体产品就可以。这样,系统的可扩展性就变得非常好,完全符合"开闭原则".
  • 工厂方法模式的缺点
  1. 在一定的程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
  2. 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
三.简单工厂方法模式实现
3.1结构图

3.2设计类图

3.3代码实现

创建工厂类HeroFactory(核心)

package com.practice.SimpleFactory;
public class HeroFactory {static Hero hero = null;public static Hero getHeroInstance(String heroTP) throws Exception {if(heroTP.equalsIgnoreCase("Tank")) {hero = new TankHero();}else if(heroTP.equalsIgnoreCase("Wild")) {hero = new WildHero();}else if(heroTP.equalsIgnoreCase("Magus")) {hero = new MagusHero();}else if(heroTP.equalsIgnoreCase("Shoot")) {hero = new ShootHero();}else if(heroTP.equalsIgnoreCase("Auxiliary")) {hero = new AuxiliaryHero();}else {throw new Exception();}return hero;}
}

创建抽象接口类Hero

package com.practice.SimpleFactory;public interface Hero {void display();
}

创建具体产品类AuxiliaryHero(辅助英雄类)

package com.practice.SimpleFactory;public class AuxiliaryHero implements Hero{public void display() {System.out.println("您的选择为:辅助(战地医生,为队友输血、解控、打鸡血)");}
}

创建具体产品类MagusHero(法师英雄类)

package com.practice.SimpleFactory;public class MagusHero implements Hero{public void display() {System.out.println("您的选择为:法师(法师,大杀器,基本就是战场上的核弹,一炸一大片,输出还十分高,最高效的人头收割器");}
}

创建具体产品类ShootHero(射手英雄类)

package com.practice.SimpleFactory;public class ShootHero implements Hero{public void display() {System.out.println("您的选择为:射手(射手,火力压制,利用大打击面形成火力网保护网中的近战英雄)");}
}

创建具体产品类TankHero(坦克英雄类)

package com.practice.SimpleFactory;public class TankHero implements Hero{public void display() {System.out.println("您的选择为:坦克(坦克主要是在前排吸收伤害,并且尽量控制敌人)");}
}

创建具体产品类WildHero(打野英雄类)

package com.practice.SimpleFactory;public class WildHero implements Hero{public void display() {System.out.println("您的选择为:打野(后排杀手,目标是在开战时以最快速度摧毁对方的输出主力)");}
}

XML配置文件(Config.xml)
通过配置文件可以极大提高系统的扩展性,让软件实体更符合开闭原则。为了让系统更符合开闭原则和依赖倒置原则,需要做到"将抽象写在代码中,将具体写在配置里"通过修改无须编译的配置文件来提高系统的可扩展性和灵活性

<?xml version="1.0" encoding="UTF-8"?>
<config><className>Tank</className>
</config>

工具类读取XML文件信息(XMLUtilHero类)
在该工具类中,通过Java语言提供的DOM(Document Object Model,文档对象模型)API来实现对XML文档的操作,在DOM API中,XML文档以树形结构存储在内存中,可以通过相关的类对XML进行读取、修改等操作

package com.practice.Client;
import java.io.File;
import javax.xml.parsers.*;
import org.w3c.dom.*;public class XMLUtilHero {//该方法用于从XML配置文件中提取英雄名称,并返回该英雄名称public static String getHeroName() {try {//创建文档对象DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dFactory.newDocumentBuilder();Document doc;doc = builder.parse(new File("src\\com\\practice\\Client\\config.xml"));//获取包含英雄名称的文本节点NodeList nl = doc.getElementsByTagName("className");Node classNode = nl.item(0).getFirstChild();String dName = classNode.getNodeValue().trim();return dName;}catch(Exception e) {e.printStackTrace();return null;}}
}

创建测试类Client类

package com.practice.Client;import com.practice.Hero.Hero;
import com.practice.HeroFactory.HeroFactory;public class Client {public static void main(String [] args) {Hero hero;HeroFactory factory;factory = (HeroFactory) XMLUtilHero.getHeroFactory();hero = factory.produceHero();hero.display();}
}

代码运行结果:

从代码结构不难看出,当我们需要添加新英雄职业比如战士类英雄时,我们必须修改工厂类,加入要处理的逻辑,这违背了"开闭原则"。在简单工厂模式中,所有的产品都是由同一个工厂创建,工厂职责较重,业务逻辑比较复杂,具体产品与工厂类之间的耦合度较高,严重影响了系统的灵活性和扩展性,而工厂方法模式则可以很好地解决这一问题。

四.用工厂方法模式实现
4.1 结构图

4.2 设计类图

4.3 代码实现

创建抽象产品类(Hero类)

package com.practice.Hero;public interface Hero {public void display();
}

创建具体产品类(AuxiliaryHero类(辅助英雄类))

package com.practice.Hero;public class AuxiliaryHero implements Hero {public void display() {System.out.println("辅助:战地医生,为队友输血、解控、打鸡血");}}

创建具体产品类(MagusHero类(法师英雄类))

package com.practice.Hero;public class MagusHero implements Hero {public void display() {System.out.println("法师:大杀器,基本就是战场上的核弹,一炸一大片,输出还十分高,最高效的人头收割器");}}

创建具体产品类(ShootHero类(射手英雄类))

package com.practice.Hero;public class ShootHero implements Hero{public void display() {System.out.println("射手:火力压制,利用大打击面形成火力网保护网中的近战英雄");}
}

创建抽象工厂类(HeroFactory)

package com.practice.HeroFactory;import com.practice.Hero.Hero;public interface HeroFactory {Hero produceHero();
}

创建具体工厂类(AuxiliaryHeroFactory(辅助工厂类))

package com.practice.HeroFactory;import com.practice.Hero.AuxiliaryHero;
import com.practice.Hero.Hero;public class AuxiliaryHeroFactory implements HeroFactory {public Hero produceHero() {System.out.println("您的选择为:辅助");return new AuxiliaryHero();}
}

创建具体工厂类(MagusHeroFactory(法师工厂类))

package com.practice.HeroFactory;import com.practice.Hero.Hero;
import com.practice.Hero.MagusHero;public class MagusHeroFactory implements HeroFactory {public Hero produceHero() {System.out.println("您的选择为:法师");return new MagusHero();}
}

创建具体工厂类(ShootHeroFactory(射手工厂类))

package com.practice.HeroFactory;import com.practice.Hero.Hero;
import com.practice.Hero.ShootHero;public class ShootHeroFactory implements HeroFactory {public Hero produceHero() {System.out.println("您的选择为:射手");return new ShootHero();}
}

配置文件XML(config.xml)

<?xml version="1.0" encoding="UTF-8"?>
<config><HeroFactory>ShootHeroFactory</HeroFactory>
</config>

辅助类(XMLUtilHero读取XML文件)

package com.practice.Client;import java.io.File;import javax.xml.parsers.*;
import org.w3c.dom.*;public class XMLUtilHero {//该方法用于从XML配置文件中提取具体类类名。并返回一个实例对象public static Object getHeroFactory() {try {//创建文档对象DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dFactory.newDocumentBuilder();Document doc;doc = builder.parse(new File("src\\com\\practice\\Client\\config.xml"));//获取包含类名的文本节点NodeList nl = doc.getElementsByTagName("HeroFactory");Node classNode = nl.item(0).getFirstChild();String HeroFactory = classNode.getNodeValue();//通过类名生成实例对象并将其返回String ClassName = "com.practice.HeroFactory."+ HeroFactory;Class<?> c = Class.forName(ClassName);@SuppressWarnings("deprecation")Object obj = c.newInstance();			return obj;}catch(Exception e) {e.printStackTrace();return null;}}
}

创建测试类(Client类)

package com.practice.Client;import com.practice.Hero.Hero;
import com.practice.HeroFactory.HeroFactory;public class Client {public static void main(String [] args) {Hero hero;HeroFactory factory;factory = (HeroFactory) XMLUtilHero.getHeroFactory();hero = factory.produceHero();hero.display();}
}

运行结果

五.源代码下载

从王者荣耀看设计模式(工厂方法模式)

更多推荐

从王者荣耀看设计模式(十三.工厂方法模式)

本文发布于:2024-02-27 13:16:03,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1706685.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:荣耀   模式   王者   工厂   方法

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!