如何将这个程序编程转换为面向对象的编程?

时间:2010-03-18 13:19:10

标签: java refactoring

我有一个需要通过创建类,对象和方法来转换的源代码。 到目前为止,我刚刚将初始main转换为单独的类。但我不知道如何处理构造函数以及哪些变量应该是私有的。这是代码:

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();

    }
}

我应该通过创建其他类来简化Card类吗?

通过这段代码,我的javadoc没有构造函数。所以我需要帮助!

6 个答案:

答案 0 :(得分:12)

  

但我不知道如何处理构造函数以及哪些变量应该是私有的。

无论是什么,都应该是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("");
   }
}

现在我们需要有人提供lengthwidth - 这就是构造函数的用途:

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 - 重命名它并继续下一个“命名原语”或{ {3}} 2

1 我使用“named primitive”来表示相同的原始类型,它是全局的或在具有相同名称的方法之间传递。由于没有类,语义意义纯粹是名称 - 通常这个名称是一个类的一个很好的起点。它与众所周知的“原始痴迷”代码气味有关,但略有不同,因为它不需要伪装成类的大量原始类型。可以将单个命名基元提升为类。

2 许多代码气味特别适用于OOP代码。为了查看您尝试转换为OO的过程代码,我认为“原始的痴迷”,“数据块”,“消息链”和“长参数列表”是最相关的。

答案 1 :(得分:8)

它看起来像经典的记忆游戏,使用卡片。我看到四个主要类别:

  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()
    

答案 2 :(得分:3)

在担心对象之前,首先应该至少将部分分成命名方法,以便更清楚每个部分在做什么。无论是否是OO,这都很重要。例如:

    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或类似的东西。

至于课程,我可能会创建一个具有cardscardstatus的Board类以及检查当前卡片的方法shuffle。在你开始工作后,我会尝试删除Board类的所有输入和输出。

重构很少是一步到位的过程。重写是一个选项,因为它是一个相对较小的程序,但请注意,您可能会重新引入一些先前修复过的错误,并且可能是一些新的错误(重构相同,但进行较小的更改会使其稍微不太可能)< / p>

答案 3 :(得分:1)

这个答案说明了一种可能的重构方法,可以使您的方法更加面向对象。它没有解决问题域(卡片,卡片等),这些问题由其他答案解决。相反,它描述了如何使用面向对象原则以更加面向对象的方式处理程序化实现。

我要做的第一步是将我称之为PromptedLoop构造的内容分解出来。你在.play中有一个do / while循环,提示用户是否要运行,当他说是,它会做一些动作。

采用此功能并封装它。使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可以只是一个播放动作的单个实例,而不必集成循环功能。然后,您可以选择将PromptedLoop重新用于其他程序,并且您可以更轻松地阅读.play,因为您可能不会因为它可能被循环而分心。

答案 4 :(得分:0)

不幸的是,将“程序”程序转换为“OO”的最佳(唯一)方法是从头开始构建它。

设计对象模型和您认为每个对象应具有的功能,并编写类和方法存根。

然后你可以回到你的原始代码,将一些功能从程序中拉出来,然后进入对象。

答案 5 :(得分:0)

此代码中可以找到各种smells。如果你真的想从中逐一阅读福勒的重构,并立即应用所有获得的知识。

另一种方法就是不要碰它,“不要修理工作引擎”。