栄光の王からの参照デザインパターン(XIV。ファクトリメソッドパターン)

栄光の王からデザインモード(Factory Methodパターン)を参照してください。

II。はじめに

栄光の英雄のスキル、属性、才能やその他の要因のゲームデザイナーの王によると、英雄はシューター、補助、遊んでフィールド、マスター、戦車、兵士や他の職業に分かれています。多くの種類から選択するヒーローのゲームがあります。ゲームの主人公の選択の選手、ゲームの勝利を勝つために合理的な基本的な保証を持つヒーロー。

III。ファクトリメソッドパターン

ファクトリメソッドモデル(ファクトリメソッドパターン):とも呼ばれる工場法モデル工場モデル、仮想コンストラクタ(仮想コンストラクタ)モードまたは多型植物(多形ファクトリー)モードと呼ばれる、クラス作成したスキーマに属します。ファクトリメソッドモードでは、工場出荷時の親クラスは、製品のオブジェクトのパブリックインターフェイスを作成して定義するための責任があり、工場のサブクラスは、特定の対象物を生成するための責任があり、その目的は、完成した植物のサブクラスへの製品クラスの遅延のインスタンス化操作にありますすなわち、インスタンス化するために特定の製品クラスファクトリサブクラスかどうかを決定することによって。

  • ファクトリメソッドパターンの使用シナリオ
  1. 彼は、オブジェクトを必要なようにクラスが知らない:Factory Methodパターンを、クライアントが知る必要はありません
    クラス名、特定の製品カテゴリを、唯一の具体的なファクトリクラスによって作成された特定の製品のオブジェクトに対応する植物を知っておく必要があり、顧客を最後には、製品固有のファクトリクラスを作成するために知っておく必要があります。
  2. クラスは、オブジェクトが作成サブクラスで指定:ファクトリーモードの方法、唯一の製品のインターフェイスを作成するための抽象ファクトリクラスでは、オブジェクトは、特定の要件を作成するためにサブクラスによって決定することができ、オブジェクト指向の多型そして、リヒター置換原則は、プログラムが拡大しやすいシステムを作る、オブジェクトのサブクラスは親クラスのオブジェクトを上書きします、実行されています
  3. 製品サブカテゴリーを作成するには、サブクラスの工場であるかもしれないものを気にせずに使用し、必要なときに動的に割り当てられたときに、タスク、特定のクライアントのオブジェクトを作成するために委託複数の工場サブクラス、特定のクラスファクトリクラスの名前にすることができます設定ファイルやデータベースに保存されています
  • 関連する工場モデルの設計原理は次のとおりです。
    ★抽象的に依存して、特定の種類に依存しない
    、拡張、変更のため閉鎖のためのオープン★され
    ★パッケージの変更
    ではないためにプログラミングするため、インターフェイスをプログラムするための★

  • 図ジェネリッククラスファクトリメソッドパターン:

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

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

四.简单工厂方法模式实现

4.1结构图

4.2设计类图

4.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();
    }
}

代码运行结果:

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

五.用工厂方法模式实现

5.1 结构图

5.2 设计类图

5.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();
    }
}

运行结果

六.源代码下载

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

おすすめ

転載: www.cnblogs.com/miaowulj/p/12146542.html