“Java中的享元模式”

huangapple go评论68阅读模式
英文:

Flyweight Pattern in Java

问题

我在链接中看到了享元模式(FlyWeight Pattern)的描述。在提供的示例中,我相信只会创建2个玩家对象的实现。难道不会在每次创建玩家对象时覆盖武器变量吗?

英文:

I came across FlyWeight Pattern described in the link. In the example provided , I believe only 2 implementations of player objects will be created. Wouldn't the weapons variable be overridden each time a player object is created?

答案1

得分: 1

在Geeks for Geeks的作者提供的示例类图中:

(图片链接)

如果我理解正确,游戏创建了一个Terrorist实例,一个CounterTerrorist实例,以及由PlayerFactory创建的nPlayer实例。

代码反映了这个类图。TerroristCounterTerrorist都实现了Player接口。

PlayerFactory创建的每个Player实例都使用来自TerroristCounterTerrorist实例的信息,这取决于玩家所在的阵营。由于每个玩家(通常在CounterStrike中为10名,每边5名),都有一个Player实例,因此不会混淆哪个玩家是哪个。

CounterStrike类管理由PlayerFactory创建的Map

这个简单的现实世界示例减少了如果只有nPlayer实例时会发生的重复。每个Player实例都必须同时保存恐怖分子和反恐分子的信息。

通过创建一个Terrorist实例,一个CounterTerrorist实例,并与Player实例共享这些实例,减少了游戏字段的总存储量。

游戏代码可能也更容易进行调试和管理。

Java代码可以在Geeks For Geeks上找到。

英文:

In the example class diagram given by the Geeks for Geeks author

“Java中的享元模式”

If I understand this correctly, the game creates one instance of Terrorist, one instance of CounterTerrorist, and n instances of Player created by the PlayerFactory.

The code reflects the diagram. Terrorist and CounterTerrorist implement the Player interface.

Each Player instance created by the PlayerFactory uses the information from the Terrorist or CounterTerrorist instance, depending on which side the player is on. Since there's a Player instance for each player (Usually 10 in CounterStrike, 5 on each side), there's no confusion as to which player is which.

The CounterStrike class manages the Map created by the PlayerFactory.

This simple real-world example minimizes the duplication that would occur if there were just n Player instances. Each Player instance would have to hold the information for both a terrorist and a counter-terrorist.

By creating one instance of Terrorist, one instance of CounterTerrorist, and sharing those instances with the Player instances, the total amount of storage for the game fields is reduced.

The game code is probably easier to debug and manage as well.

The Java code can be found on Geeks For Geeks.

答案2

得分: 1

以下是您提供的代码部分的翻译:

// ...(略去开头的说明)

public class CounterStrike
{
    public enum PlayerType{

        TERRORIST("PLANT A BOMB"), COUNTER_TERRORIST("DIFFUSE BOMB");

        private final String task;

        PlayerType(String task){
            this.task = task;
        }

        String getTask(){ return task; }
    }

    public enum Weapon {

        AK47("AK-47"), MAVERICK("Maverick"), GUT_KNIFE("Gut Knife"), DESERT_EAGLE("Desert Eagle");

        private final String name;

        Weapon(String name) {  this.name = name; }

        String getName(){ return name; }

        @Override
        public String toString() { return name; }
    }

    public static void main(String args[])
    {
        List<Player> players = new ArrayList<>();

        System.out.println("-------  玩家构造  ----------------");
        for (int i = 0; i < 10; i++)
        {
            Player p = PlayerFactory.getPlayer(getRandPlayerType(), getRandWeapon()) ;
            players.add(p);
            System.out.println("创建了:" + p);
        }

        System.out.println("-------  打印所有玩家 ----------------");
        for(Player p : players) {  System.out.println(p);  }
    }

    public static PlayerType getRandPlayerType()
    {
        int randInt =  new Random().nextInt(PlayerType.values().length);
        return PlayerType.values()[randInt];
    }

    public static Weapon getRandWeapon()
    {
        int randInt =  new Random().nextInt(Weapon.values().length);
        return Weapon.values()[randInt];
    }
}

class PlayerFactory
{
    private static HashMap<Weapon, Player> terrorists =  new HashMap<>();
    private static HashMap<Weapon, Player> cTerrorists =  new HashMap<>();

    static Player getPlayer(PlayerType type, Weapon weapon) {

        return type == PlayerType.TERRORIST ? getTerrorist(weapon) : getCounterTerrorist(weapon);
    }

    private static Player getTerrorist(Weapon weapon)
    {
        Player p = null;

        if (terrorists.containsKey(weapon)) {
            p = terrorists.get(weapon);
        } else{
            p = new Player(PlayerType.TERRORIST, weapon);
        }
        terrorists.put(weapon, p);
        return p;
    }

    private static Player getCounterTerrorist(Weapon weapon)
    {
        Player p = null;

        if (cTerrorists.containsKey(weapon)) {
            p = cTerrorists.get(weapon);
        } else{
            p = new Player(PlayerType.COUNTER_TERRORIST, weapon);
        }
        cTerrorists.put(weapon, p);
        return p;
    }
}

class Player
{
    private final Weapon weapon;
    private final PlayerType type;

    Player(PlayerType type, Weapon weapon) {
        this.type = type;
        this.weapon = weapon;
    }

    Weapon getWeapon() { return weapon; }

    PlayerType getType() {return type; }

    String getTask() {  return type.getTask(); }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(type == PlayerType.TERRORIST ? "Terrorist" : "Counter Terrorist" );
        sb.append(" 携带武器:").append(weapon).append(". 任务:").append(type.getTask());
        return sb.toString();
    }
}

请注意,上述翻译中的注释已被省略,只保留了代码部分的翻译。如果您有任何问题或需要进一步帮助,请随时提问。

英文:

The code as posted on Geeks For Geeks constructs only two mutable objects. <br/>
As can be expected, each time PlayerFactory returns a player, it overrides the weapon of one of the two objects. <br/>
This can be demonstrated easily:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
public class CounterStrike
{
private static String[] playerType = {&quot;Terrorist&quot;, &quot;CounterTerrorist&quot;};
private static String[] weapons = {&quot;AK-47&quot;, &quot;Maverick&quot;, &quot;Gut Knife&quot;, &quot;Desert Eagle&quot;};
public static void main(String args[])
{
List&lt;Player&gt; players = new ArrayList&lt;&gt;();
System.out.println(&quot;-------  Construction of Players  ----------------&quot;);
for (int i = 0; i &lt; 10; i++)
{
Player p = PlayerFactory.getPlayer(getRandPlayerType());
p.assignWeapon(getRandWeapon());
p.mission();
players.add(p);
}
System.out.println(&quot;-------  Printout all players ----------------&quot;);
for(Player p : players) {
p.mission();
}
}
public static String getRandPlayerType()
{
// Will return 0 or 1
int randInt =  new Random().nextInt(playerType.length);
return playerType[randInt];
}
public static String getRandWeapon()
{
// Will return an integer between 0 inclusive and 5 exclusive
int randInt = new Random().nextInt(weapons.length);
return weapons[randInt];
}
}
interface Player
{
void assignWeapon(String weapon);
void mission();
}
class Terrorist implements Player
{
private final String TASK;
private String weapon;
public Terrorist()
{
TASK = &quot;PLANT A BOMB&quot;;
}
@Override
public void assignWeapon(String weapon)
{
this.weapon = weapon;
}
@Override
public void mission()
{
System.out.println(&quot;Terrorist with weapon &quot; + weapon + &quot;|&quot; + &quot; Task is &quot; + TASK);
}
}
class CounterTerrorist implements Player
{
private final String TASK;
private String weapon;
public CounterTerrorist()
{
TASK = &quot;DIFFUSE BOMB&quot;;
}
@Override
public void assignWeapon(String weapon)
{
this.weapon = weapon;
}
@Override
public void mission()
{
System.out.println(&quot;Counter Terrorist with weapon &quot;+ weapon + &quot;|&quot; + &quot; Task is &quot; + TASK);
}
}
class PlayerFactory
{
private static HashMap &lt;String, Player&gt; hm =  new HashMap&lt;&gt;();
public static Player getPlayer(String type)
{
Player p = null;
if (hm.containsKey(type)) {
p = hm.get(type);
} else
{
switch(type)
{
case &quot;Terrorist&quot;:
p = new Terrorist();
break;
case &quot;CounterTerrorist&quot;:
p = new CounterTerrorist();
break;
default :
System.out.println(&quot;Unreachable code!&quot;);
}
hm.put(type, p);
}
return p;
}
}

The output shows that all Terrorist have the last applied weapon (Maverick) and all CT an AK-47:
“Java中的享元模式”

<hr>
Edit: I did not explore this design pattern, but I must say I am not impressed by the code posted in Geeks For Geeks.<br/>
From what I see in other examples the extrinsic attributes need to be managed by the factory. <br/>
In this case I guess the factory should have a map for terrorist and a map for CT where the key is the weapon:

public class CounterStrike
{
//better use enums
private static String[] playerType = {&quot;Terrorist&quot;, &quot;CounterTerrorist&quot;};
private static String[] weapons = {&quot;AK-47&quot;, &quot;Maverick&quot;, &quot;Gut Knife&quot;, &quot;Desert Eagle&quot;};
public static void main(String args[])
{
List&lt;Player&gt; players = new ArrayList&lt;&gt;();
System.out.println(&quot;-------  Construction of Players  ----------------&quot;);
for (int i = 0; i &lt; 10; i++)
{
String type = getRandPlayerType();
Player p = type.equals(playerType[0]) ?  PlayerFactory.getTerrorist(getRandWeapon()) :
PlayerFactory.getCoubterTerrorist(getRandWeapon()) ;
p.mission();
players.add(p);
}
System.out.println(&quot;-------  Printout all players ----------------&quot;);
for(Player p : players) {
p.mission();
}
}
public static String getRandPlayerType()
{
// Will return 0 or 1
int randInt =  new Random().nextInt(playerType.length);
return playerType[randInt];
}
public static String getRandWeapon()
{
// Will return an integer between 0 inclusive and 5 exclusive
int randInt = new Random().nextInt(weapons.length);
return weapons[randInt];
}
}
class PlayerFactory
{
private static HashMap &lt;String, Player&gt; terrorists =  new HashMap&lt;&gt;();
private static HashMap &lt;String, Player&gt; cTerrorists =  new HashMap&lt;&gt;();
public static Player getTerrorist(String weapon)
{
Player p = null;
if (terrorists.containsKey(weapon)) {
p = terrorists.get(weapon);
} else{
p = new Terrorist(weapon);
}
terrorists.put(weapon, p);
return p;
}
public static Player getCoubterTerrorist(String weapon)
{
Player p = null;
if (cTerrorists.containsKey(weapon)) {
p = cTerrorists.get(weapon);
} else{
p = new CounterTerrorist(weapon);
}
cTerrorists.put(weapon, p);
return p;
}
}
interface Player
{
void mission();
}
class Terrorist implements Player
{
private final String TASK;
private String weapon;
public Terrorist(String weapon)
{
this.weapon = weapon;
TASK = &quot;PLANT A BOMB&quot;;
}
@Override
public void mission()
{
System.out.println(&quot;Terrorist with weapon &quot; + weapon + &quot;|&quot; + &quot; Task is &quot; + TASK);
}
}
class CounterTerrorist implements Player
{
private final String TASK;
private String weapon;
public CounterTerrorist(String weapon)
{
this.weapon = weapon;
TASK = &quot;DIFFUSE BOMB&quot;;
}
@Override
public void mission()
{
System.out.println(&quot;Counter Terrorist with weapon &quot;+ weapon + &quot;|&quot; + &quot; Task is &quot; + TASK);
}
}

We can improve the implementation by using enums, and making the player type an intrinsic attribute, rather than a class:

public class CounterStrike
{
public enum PlayerType{
TERRORIST(&quot;PLANT A BOMB&quot;), COUNTER_TERRORIST(&quot;DIFFUSE BOMB&quot;);
private final String task;
PlayerType(String task){
this.task = task;
}
String getTask(){ return task; 	}
}
public enum Weapon {
AK47(&quot;AK-47&quot;), MAVERICK(&quot;Maverick&quot;), GUT_KNIFE(&quot;Gut Knife&quot;), DESERT_EAGLE(&quot;Desert Eagle&quot;);
private final String name;
Weapon(String name) { 	this.name = name; 	}
String getName(){ return name; 	}
@Override
public String toString() { return name; }
}
public static void main(String args[])
{
List&lt;Player&gt; players = new ArrayList&lt;&gt;();
System.out.println(&quot;-------  Construction of Players  ----------------&quot;);
for (int i = 0; i &lt; 10; i++)
{
Player p = PlayerFactory.getPlayer(getRandPlayerType(), getRandWeapon()) ;
players.add(p);
System.out.println(&quot;Created: &quot;+ p);
}
System.out.println(&quot;-------  Printout all players ----------------&quot;);
for(Player p : players) { 	System.out.println(p); 	}
}
public static PlayerType getRandPlayerType()
{
int randInt =  new Random().nextInt(PlayerType.values().length);
return PlayerType.values()[randInt];
}
public static Weapon getRandWeapon()
{
int randInt =  new Random().nextInt(Weapon.values().length);
return Weapon.values()[randInt];
}
}
class PlayerFactory
{
private static HashMap &lt;Weapon, Player&gt; terrorists =  new HashMap&lt;&gt;();
private static HashMap &lt;Weapon, Player&gt; cTerrorists =  new HashMap&lt;&gt;();
static Player getPlayer(PlayerType type, Weapon weapon) {
return type == PlayerType.TERRORIST ? getTerrorist(weapon) : getCounterTerrorist(weapon);
}
private static Player getTerrorist(Weapon weapon)
{
Player p = null;
if (terrorists.containsKey(weapon)) {
p = terrorists.get(weapon);
} else{
p = new Player(PlayerType.TERRORIST, weapon);
}
terrorists.put(weapon, p);
return p;
}
private static Player getCounterTerrorist(Weapon weapon)
{
Player p = null;
if (cTerrorists.containsKey(weapon)) {
p = cTerrorists.get(weapon);
} else{
p = new Player(PlayerType.COUNTER_TERRORIST, weapon);
}
cTerrorists.put(weapon, p);
return p;
}
}
class Player
{
private final Weapon weapon;
private final PlayerType type;
Player(PlayerType type, Weapon weapon) {
this.type = type;
this.weapon = weapon;
}
Weapon getWeapon() { return weapon; }
PlayerType getType() {return type; }
String getTask() { 	return type.getTask(); }
@Override
public String toString() {
StringBuilder sb = new StringBuilder(type == PlayerType.TERRORIST ? &quot;Terrorist&quot; : &quot;Counter Terrorist&quot; );
sb.append(&quot; armed with &quot;).append(weapon).append(&quot;. Task: &quot;).append(type.getTask());
return sb.toString();
}
}

huangapple
  • 本文由 发表于 2020年5月2日 12:34:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/61554507.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定