2010-05-06 2 views
2

Если кто-то знаком с Ребеккой Вирфс-Брок, у нее есть кусок кода Java, который был найден в ее книге под названием «Дизайн объекта: роли, обязанности и сотрудничество».Нужна помощь в экстраполяции кода Java

Вот цитата>Применяя двойную диспетчеризацию к конкретной задаче Для реализации игры Rock, Paper, Scissors, нам нужно написать код, который определяет, будет ли «обыгрывает» один объект другому. В игре есть девять возможных результатов, основанных на трех видах объектов . Количество взаимодействий - это перекрестное произведение видов объектов. Операторы case или switch часто регулируются типом данных, которые работают. Объектно-ориентированный эквивалент языка должен основывать свои действия на классе другого объекта. В Java это выглядит Вот фрагмент Java-кода на странице 16 «

import java.util.*;  
    import java.lang.*; 

public class Rock 
{ 
public static void main(String args[]) 
{ 

} 

public static boolean beats(GameObject object) 
{ 
    if (object.getClass.getName().equals("Rock")) 
    { 
     result = false; 
    } 
    else if (object.getClass.getName().equals("Paper")) 
    { 
     result = false;   
    } 
    else if(object.getClass.getName().equals("Scissors")) 
    { 
      result = true; 
    } 
    return result; 
} 

===> Это не очень хорошее решение. Во-первых, приемник должен слишком много знать об этом аргументе. Во-вторых, есть один из этих вложенных условных операторов в каждом из трех классов. Если в игру могут быть добавлены новые объекты , каждый из трех классов должен быть изменен. Может ли кто-нибудь поделиться со мной, как заставить эту «менее оптимальную» часть кода работать, чтобы увидеть ее «работающую». Она продолжает демонстрировать лучший путь, но я пощажу вас. Благодаря

ответ

-2

Так вот как я его исправил. Сначала я создал новый интерфейс GameObject, так как они ссылаются на него!

public interface GameObject 
{ 
public boolean beats(GameObject g); 
} 

Тип не существует, поэтому ссылка на него не будет работать так хорошо.

Вот мой новый код для Rock с комментариями об изменениях:

import java.util.*; 
import java.lang.*; 

public class Rock implements GameObject //Need to be an instance of GameObject somehow! 
{ 
public static void main(String args[]) 
    { 

    } 

public boolean beats(GameObject object) //This isn't static anymore 
{ 
boolean result = false; //Need to declare and initialize result 
if (((Object)object).getClass().getName().equals("Rock")) //getClass should have() 
    { 
    result = false; 
    } 
else if (object.getClass().getName().equals("Paper")) //getClass should have() 
    { 
    result = false; 
    } 
else if(object.getClass().getName().equals("Scissors")) //getClass should have() 
    { 
    result = true; 
    } 
return result; 
} 
} 

EDIT: Вы, казалось, с просьбой о том, как исправить код и не лучший способ сделать это. Я считаю, что это должно быть хорошо, чтобы пойти за тобой сейчас.

+0

Хорошо, спасибо за комментарии к изменениям и код, это здорово. И ДА, я пытаюсь исправить свой код, чтобы скорректировать «плохой» пример, который она приводит в своей первой главе книги. Большое спасибо за код! – dannyrosalex

+0

Почему люди голосуют за это? Это то, что он искал. Если у вас есть конструктивная критика о том, что происходит не так, оставьте комментарий. Никто не говорит, что это лучший способ решить проблему, это был пример на пути к лучшему решению в его книге, и у него возникли проблемы с его компиляцией, которую я исправил. –

1

Я думаю, что лично у меня просто был бы класс полезности, который бы содержал метод «биты». В методе «биты» в качестве параметров будут задействованы два объекта GameObject.

Таким образом, я мог бы просто передать два объекта (камень, бумага или ножницы) и выполнить необходимую логику. Теперь, если вы добавляете новый объект, вы не изменяете ничего, кроме метода «beats» в классе утилит, сохраняя вещи, инкапсулированные из вашего основного.

Ссылка ryan хороша, она содержит несколько других идей для обработки этой ситуации.

+0

Я не думаю, что главная должен идти туда, где я его разместил. Это совсем нет в книге Ребекки. Я просто пытался проверить это. Поскольку я новичок в Java (я кодер .NET), должен ли я найти основной файл в другом файле? Я использую Notepad ++ для редактирования своих java-файлов и командной строки для компиляции – dannyrosalex

2

Используйте enum для работы с ним (RPSObj), который имеет метод beats(RPSObj o), с каждым перечислимомом элементом, имеющим Set принятым в, хранится в виде beatset.Затем метод beats(RPSObj o) может делать return beatset.contains(o);. Simples :)

Edit: Вы можете использовать в качестве EnumSet реализации Set, которая должна быть еще более эффективной, чем другие реализации набора :)

+0

Я кодер .Net, обманывающий Java, чтобы изучить хороший дизайн объекта (БОГ). Я не знал, что у вас может быть метод, определенный в Enum. Может быть, я совершенно незнаю, но я не знал, что вы можете сделать это на любом языке. – dannyrosalex

+0

Хорошее, простое решение. – digitaljoel

+0

@Berlioz вы можете посмотреть на http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html –

3

Я хотел бы начать с определения классов RPSSystem и RPSObject. Код для построения классической RPS-игра будет выглядеть следующим образом:

RPSObject rock = new RPSObject("Rock"); 
RPSObject paper = new RPSObject("Paper"); 
RPSObject scissors = new RPSObject("Scissors"); 
RPSSystem classicRPS = new RPSSystem(rock, paper, scissors); 
// new RPSSystem(Collection<RPSObject> objects) possible too 
classicRPS.defineBeatsRule(rock, scissors); 
classicRPS.defineBeatsRule(paper, rock); 
classicRPS.defineBeatsRule(scissors, paper); 

RPSSystem бы метод

int fight(RPSObject a, RPSObject b) 

возвращающие бы -1, когда a побед, 1, когда b побед и 0, когда результат не определен. Внутренне RPSObjects могут быть сохранены в списке, и правила биения могут быть сохранены в матрице (столбцы и строки будут соответствовать индексам объектов в списке). Если несколько экземпляров аналогичного RPSObject должны быть разрешены, эквивалентный метод RPSObject должен быть написан соответствующим образом.

Наличие отдельного класса для каждого объекта в системе кажется слишком сложным.

EDIT:

Полные классы:

package rpsgame; 

public final class RPSObject { 
    private final String name; 

    public RPSObject(String name) { 
     this.name = name; 
    } 

    public String getName() { 
     return name; 
    } 

    public String toString() { 
     return getName(); 
    } 
} 

package rpsgame; 

import java.util.Arrays; 
import java.util.Collections; 
import java.util.List; 

public final class RPSSystem { 

    private final List<RPSObject> objects; 
    private final int[][] beatsRules; 

    public static final int WINS = 1; 
    public static final int TIE = 0; 
    public static final int LOSES = -1; 


    public RPSSystem(RPSObject... objects) { 
     this.objects = Arrays.asList(objects.clone()); 
     this.beatsRules = new int[objects.length][objects.length]; 
    } 

    void defineBeatsRule(RPSObject winner, RPSObject loser) { 
     if (winner.equals(loser)) throw new IllegalArgumentException(); 

     int winnerIndex = getObjectIndex(winner); 
     int loserIndex = getObjectIndex(loser); 

     beatsRules[winnerIndex][loserIndex] = WINS; 
     beatsRules[loserIndex][winnerIndex] = LOSES; 
    } 

    public int fight(RPSObject a, RPSObject b) { 
     int aIndex = getObjectIndex(a); 
     int bIndex = getObjectIndex(b); 

     return beatsRules[aIndex][bIndex]; 
    } 

    public List<RPSObject> getObjects() { 
     return Collections.unmodifiableList(objects); 
    } 

    private int getObjectIndex(RPSObject o) { 
     int index = objects.indexOf(o); 
     if (index < 0) throw new IllegalArgumentException(); 
     return index; 
    } 

    // test 
    public static void main(String[] args) { 

     RPSSystem classicRPS = buildClassicRPS(); 

     List<RPSObject> objects = classicRPS.getObjects(); 

     for (RPSObject a: objects) { 
      for (RPSObject b: objects) { 
       int result = classicRPS.fight(a, b); 
       switch (result) { 
        case RPSSystem.WINS: 
         System.out.println(a + " beats " + b); 
         break; 
        case RPSSystem.TIE: 
         System.out.println(a + " vs " + b + " is tied"); 
         break; 
        case RPSSystem.LOSES: 
         System.out.println(a + " loses against " + b); 
         break; 
       } 
      } 
     } 
    } 

    private static RPSSystem buildClassicRPS() { 
     RPSObject rock = new RPSObject("Rock"); 
     RPSObject paper = new RPSObject("Paper"); 
     RPSObject scissors = new RPSObject("Scissors"); 

     RPSSystem classicRPS = new RPSSystem(rock, paper, scissors); 

     classicRPS.defineBeatsRule(rock, scissors); 
     classicRPS.defineBeatsRule(paper, rock); 
     classicRPS.defineBeatsRule(scissors, paper); 
     return classicRPS; 
    } 
} 

Просто добавьте RPSSystem.EVERYONE_DIES и defineEveryoneDiesRule(...), и вы будете готовы к

rps.add(atombomb); 
rps.defineBeatsRule(atombomb, scissors); 
rps.defineBeatsRule(atombomb, rock); 
rps.defineBeatsRule(atombomb, paper); 
rps.defineEveryoneDiesRule(atombomb, atombomb); 
+0

Спасибо, что поделились своим кодом со мной. – dannyrosalex