Как преобразовать это процедурное программирование в объектно-ориентированное программирование?

У меня есть исходный код, который необходим, чтобы быть преобразованным путем создания классов, объектов и методов. До сих пор я только что сделал путем преобразования начального основного в отдельный класс. Но я не знаю, что сделать с конструктором и какие переменные, как предполагается, являются частными. Это - код:

import java.util.*;

public class Card{

private static void shuffle(int[][] cards){

    List<Integer> randoms = new ArrayList<Integer>();
    Random randomizer = new Random();

    for(int i = 0; i < 8;) {
      int r = randomizer.nextInt(8)+1;
      if(!randoms.contains(r)) {
        randoms.add(r);
        i++;
      }
    }

    List<Integer> clonedList = new ArrayList<Integer>();
    clonedList.addAll(randoms);
    Collections.shuffle(clonedList);
    randoms.addAll(clonedList);
    Collections.shuffle(randoms);

    int i=0;

    for(int r=0; r < 4; r++){
        for(int c=0; c < 4; c++){
            cards[r][c] = randoms.get(i);
            i++;
        }
    }
}

public static void play() throws InterruptedException {

    int ans = 1;
    int preview;
    int r1,c1,r2,c2;
    int[][] cards = new int[4][4];
    boolean[][] cardstatus = new boolean[4][4];
    boolean gameover = false;
    int moves;
    Scanner input = new Scanner(System.in);

    do{
        moves = 0;

        shuffle(cards);

        System.out.print("Enter the time(0 to 5) in seconds for the preview of the answer : ");
        preview = input.nextInt();

        while((preview<0) || (preview>5)){
            System.out.print("Invalid time!! Re-enter time(0 - 5) : ");
            preview = input.nextInt();
        }

        preview = 1000*preview;
        System.out.println(" ");

        for (int i =0; i<4;i++){
            for (int j=0;j<4;j++){

                System.out.print(cards[i][j]);
                System.out.print(" ");
            }
            System.out.println("");
            System.out.println("");
        }

        Thread.sleep(preview);

        for(int b=0;b<25;b++){
            System.out.println(" ");
        }

        for(int r=0;r<4;r++){
            for(int c=0;c<4;c++){
                System.out.print("*");
                System.out.print(" ");
                cardstatus[r][c] = false;
            }
            System.out.println("");
            System.out.println(" ");
        }

        System.out.println("");

        do{
            do{
                System.out.print("Please insert the first card row : ");
                r1 = input.nextInt();
                while((r1<1) || (r1>4)){
                    System.out.print("Invalid coordinate!! Re-enter first card row : ");
                    r1 = input.nextInt();
                }

                System.out.print("Please insert the first card column : ");
                c1 = input.nextInt();
                while((c1<1) || (c1>4)){
                        System.out.print("Invalid coordinate!! Re-enter first card column : ");
                        c1 = input.nextInt();
                }

                if(cardstatus[r1-1][c1-1] == true){
                    System.out.println("The card is already flipped!! Select another card.");
                    System.out.println("");
                }
            }while(cardstatus[r1-1][c1-1] != false);

            do{
                System.out.print("Please insert the second card row : ");
                r2 = input.nextInt();
                while((r2<1) || (r2>4)){
                    System.out.print("Invalid coordinate!! Re-enter second card row : ");
                    r2 = input.nextInt();
                }

                System.out.print("Please insert the second card column : ");
                c2 = input.nextInt();
                while((c2<1) || (c2>4)){
                    System.out.print("Invalid coordinate!! Re-enter second card column : ");
                    c2 = input.nextInt();
                }

                if(cardstatus[r2-1][c2-1] == true){
                    System.out.println("The card is already flipped!! Select another card.");
                }
                if((r1==r2)&&(c1==c2)){
                    System.out.println("You can't select the same card twice!!");
                    continue;
                }
            }while(cardstatus[r2-1][c2-1] != false);

            r1--;
            c1--;
            r2--;
            c2--;

            System.out.println("");
            System.out.println("");
            System.out.println("");

            for(int r=0;r<4;r++){
                for(int c=0;c<4;c++){

                    if((r==r1)&&(c==c1)){
                        System.out.print(cards[r][c]);
                        System.out.print(" ");
                    }
                    else if((r==r2)&&(c==c2)){
                        System.out.print(cards[r][c]);
                        System.out.print(" ");
                    }
                    else if(cardstatus[r][c] == true){
                        System.out.print(cards[r][c]);
                        System.out.print(" ");
                    }
                    else{
                        System.out.print("*");
                        System.out.print(" ");
                    }
                }
                System.out.println(" ");
                System.out.println(" ");
            }

            System.out.println("");

            if(cards[r1][c1] == cards[r2][c2]){
                System.out.println("Cards Matched!!");

                cardstatus[r1][c1] = true;
                cardstatus[r2][c2] = true;
            }
            else{
                System.out.println("No cards match!!");
            }

            Thread.sleep(2000);

            for(int b=0;b<25;b++){
                System.out.println("");
            }

            for(int r=0;r<4;r++){
                for(int c=0;c<4;c++){
                    if(cardstatus[r][c] == true){
                        System.out.print(cards[r][c]);
                        System.out.print(" ");
                    }
                    else{
                        System.out.print("*");
                        System.out.print(" ");
                    }
                }
                System.out.println("");
                System.out.println(" ");
            }

            System.out.println("");
            System.out.println("");
            System.out.println("");

            gameover = true;

            for(int r=0;r<4;r++){
                for( int c=0;c<4;c++){
                    if(cardstatus[r][c]==false){
                        gameover = false;
                        break;
                    }
                }
                if(gameover==false){
                    break;
                }
            }

            moves++;

        }while(gameover != true);

        System.out.println("Congratulations, you won!!");
        System.out.println("It required " + moves + " moves to finish it.");
        System.out.println("");
        System.out.print("Would you like to play again? (1=Yes / 0=No) : ");
        ans = input.nextInt();

    }while(ans == 1);


}


}

Основной класс:

import java.util.*;

public class PlayCard{

public static void main(String[] args) throws InterruptedException{

    Card game = new Card();
    game.play();

    }
}

Я должен упростить класс Карты путем создания других классов?

Через этот код мой javadoc не имеет никакого конструктора. Таким образом, я нуждаюсь в помощи на этом!

7
задан Roman 18 March 2010 в 13:25
поделиться

6 ответов

Но я не знаю, что делать с конструктором и какие переменные должны быть приватными.

Все, что может быть, должно быть private. Чтобы определить это, часто проще всего пометить все private, а затем, когда вы достигнете "болевой точки", перевести это в public.

Что касается того, какие классы вам нужны, посмотрите на существующий код на предмет "запахов", например:

int[][] cards = new int[4][4];

У вас там есть "именованный примитив"1 - и он используется довольно часто. Это делает его важным существительным для вашей программы. Инкапсулируйте его в класс:

public class Cards {
   private int[][] cards = new int[4][4];
}

Теперь поищите, где вы манипулируете этим именованным примитивом:

shuffle(cards);

for (int i = 0; i < 4; i++){
   for (int j = 0; j < 4; j++){
       System.out.print(cards[i][j]);
       System.out.print(" ");
   }
   System.out.println("");
   System.out.println("");
}

Это главные цели для методов:

public class Cards {
   private int[][] cards = new int[4][4];

   public void shuffle() {
      // existing shuffle method goes here - but works with private cards
   }

   public void print() {
      for (int i = 0; i < 4; i++){
        for (int j = 0; j < 4; j++){
           System.out.print(cards[i][j]);
           System.out.print(" ");
        }
      System.out.println("");
      System.out.println("");
   }
}

А затем - посмотрите на простые способы обобщения. Cards в настоящее время жестко закодирован на доску 4 x 4 - давайте параметризируем это:

public class Cards {
   private int width;
   private int length;
   private int[][] cards;

   public void shuffle() {
      // existing shuffle method goes here - but works with private cards
   }

   public void print() {
      for (int i = 0; i < length; i++){
        for (int j = 0; j < width; j++){
           System.out.print(cards[i][j]);
           System.out.print(" ");
        }
      System.out.println("");
      System.out.println("");
   }
}

Теперь нам нужно, чтобы кто-то предоставил length и width - вот для чего нужны конструкторы:

public class Cards {
    private int width;
    private int length;
    private int[][] cards;

   public Cards(int length, int width) {
      this.length = length;
      this.width = width;
      this.cards = new int[length][width];
   }

   public void shuffle() {
      // existing shuffle method goes here - but works with private cards
   }

   public void print() {
      for (int i = 0; i < length; i++){
        for (int j = 0; j < width; j++){
           System.out.print(cards[i][j]);
           System.out.print(" ");
        }
      System.out.println("");
      System.out.println("");
   }
}

И тут мы понимаем, что Cards - не такое уж хорошее имя для этого. ...Это скорее Board - переименуем его и перейдем к следующему "именованному примитиву" или smell2.

1 Я использую "именованный примитив" для обозначения одного и того же примитивного типа, который либо является глобальным, либо передается между методами с тем же именем. Поскольку класса нет, семантический смысл заключается исключительно в имени - часто это имя является отличной отправной точкой для класса. Это связано с хорошо известным запахом кода "навязчивости примитивов", но немного отличается тем, что не требует большого количества примитивных типов, маскирующихся под класс. Один именованный примитив может быть переведен в класс.

2 Многие запахи кода характерны именно для ООП-кода. Для процедурного кода, который вы пытаетесь преобразовать в ООП, я думаю, наиболее актуальны "навязчивость примитивов", "сгустки данных", "цепочки сообщений" и "длинные списки параметров".

12
ответ дан 6 December 2019 в 07:25
поделиться

Прежде чем беспокоиться об объектах, вы должны сначала хотя бы разделить разделы на именованные методы, чтобы было более понятно, что делает каждая часть. Это важно, ОО или нет. Например:

    for (int i =0; i<4;i++){
        for (int j=0;j<4;j++){

            System.out.print(cards[i][j]);
            System.out.print(" ");
        }
        System.out.println("");
        System.out.println("");
    }

выглядит так, как будто печатает доску. Сделайте это отдельной функцией и назовите ее printBoard или что-то подобное.

Что касается классов, я бы, вероятно, сделал класс Board, который имеет ваши карты и cardstatus и методы для проверки текущей карты, а также, возможно, перемешать . После того, как вы получите эту работу, я попытаюсь удалить весь ввод и вывод из класса Board.

Рефакторинг редко бывает одноэтапным процессом. Перезапись - это вариант, поскольку это относительно небольшая программа, но имейте в виду, что вы, вероятно, повторно внесете некоторые ошибки, которые вы исправили ранее, и, возможно, некоторые новые в процессе (то же самое с рефакторингом, но внесение небольших изменений делает его немного менее вероятным)

3
ответ дан 6 December 2019 в 07:25
поделиться

К сожалению, лучший (единственный) способ преобразовать "процедурную" программу в объектно ориентированную - это создать ее с нуля.

Разработайте свою объектную модель и функциональные возможности, которые, по вашему мнению, должен иметь каждый объект, и напишите классы и заглушки методов.

Затем вы можете вернуться к исходному коду и вытащить часть этого функционала из процедур в объекты.

0
ответ дан 6 December 2019 в 07:25
поделиться

Похоже на классическую игру на память с карточками. Я вижу четыре основных класса:

  1. Игра
  2. Колода
  3. Карточка
  4. Сетка

Вот некоторые предлагаемые свойства и методы для каждого. Он неполный, но должен помочь вам.

Game
  previewDuration
  selectedRow
  selectedColumn
  selectedMatchRow
  selectedMatchColumn
  deck
  grid
  main()
  promptForColumn()
  promptForRow()
  preview()
  loadGrid()

Deck
  cardCount
  shuffle()
  getNextCard()

Card
  caption
  equals()

Grid
  width
  height
  getCardAtPos()
8
ответ дан 6 December 2019 в 07:25
поделиться

Этот ответ иллюстрирует один возможный рефакторинг, который вы можете сделать, чтобы сделать ваш подход более объектно-ориентированным. Он не затрагивает проблемную область (карты, колоды и т. Д.), На которую обращаются другие ответы. Вместо этого в нем описывается, как можно использовать принципы объектно-ориентированного программирования для решения проблем программной реализации более объектно-ориентированным способом.

Первый шаг, который я бы сделал, - это исключить то, что я назову конструкцией PromptedLoop. У вас есть цикл do / while в .play, который подсказывает пользователю, запускать или нет, и, хотя он говорит «да», он выполняет какое-то действие.

Возьмите эту функциональность и инкапсулируйте ее. Сделайте Card объектом Runnable и позвольте PromptedLoop запускать его повторно.

public interface Runnable
{
    public void Run();
}

public class PromptedLoop()
{
    private Runnable runner;
    private String prompt;

    public PromptedLoop(Runnable runner)
    {
        this.runner = runner;
        this.prompt = "Again? (1=Yes / 0=No):";
    }

    public PromptedLoop(Runnable runner, String prompt)
    {
        this.runner = runner;
        this.prompt = prompt;
    }

    public void Go()
    {
        int ans = 0;
        do
        {
            runner.Run();
            System.out.println("");
            System.out.print(prompt);
            ans = input.nextInt();
        } while(ans == 1);
    }
}

class Card
implements Runnable
{
    public void Run()
    {
        play();
    }
    ...
}

public class PlayCard {
    public static void main(String[] args) throws InterruptedException
    {
        Card game = new Card();
        PromptedLoop loop = new PromptedLoop(game, "Would you like to play again? (1=Yes, 0=No)");
        loop.Go();
    }

Тогда .play может быть всего лишь одним экземпляром действия play и не должен интегрировать функциональность цикла. Затем у вас есть возможность повторно использовать PromptedLoop для других программ, и вам будет легче читать .play, поскольку вас не отвлекает тот факт, что он может быть зациклен.

1
ответ дан 6 December 2019 в 07:25
поделиться

В этом коде можно найти все виды запахов . Если вы действительно хотите сделать из него хороший код, прочтите главу за главой «Рефакторинг» Фаулера и немедленно примените все полученные знания.

Другой подход - просто не трогайте его, «не ремонтируйте работающий двигатель».

0
ответ дан 6 December 2019 в 07:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: