Java 如何将这个过程编程转换为面向对象编程?

Java 如何将这个过程编程转换为面向对象编程?,java,refactoring,Java,Refactoring,我有一个需要通过创建类、对象和方法来转换的源代码。 到目前为止,我只是将最初的main转换成一个单独的类。但我不知道如何使用构造函数,哪些变量应该是私有的。代码如下: import java.util.*; public class Card{ private static void shuffle(int[][] cards){ List<Integer> randoms = new ArrayList<Integer>(); Random ran

我有一个需要通过创建类、对象和方法来转换的源代码。 到目前为止,我只是将最初的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);


}


}
我应该通过创建其他类来简化卡片类吗

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

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

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

然后,您可以返回到原始代码,从过程中提取一些函数并将其放入对象中。

在此代码中可以找到各种类型的函数。如果你真的想从中产生好的代码,那就一章一章地阅读Fowler的重构,并立即应用所有获得的知识


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

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

  • 游戏
  • 甲板
  • 卡片
  • 网格
  • 下面是针对每种方法的一些建议属性和方法。这是不完整的,但它应该让你走

    Game
      previewDuration
      selectedRow
      selectedColumn
      selectedMatchRow
      selectedMatchColumn
      deck
      grid
      main()
      promptForColumn()
      promptForRow()
      preview()
      loadGrid()
    
    Deck
      cardCount
      shuffle()
      getNextCard()
    
    Card
      caption
      equals()
    
    Grid
      width
      height
      getCardAtPos()
    

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

    我要做的第一步是计算出我将称之为PromptedLoop的构造。在.play中有一个do/while循环,提示用户是否运行,当用户说是时,它会执行一些操作

    将此功能封装起来。使卡成为可运行对象,并允许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,这样您可以更轻松地阅读。播放时,您不会因为它可能会被循环而分心。

    在担心对象之前,您应该首先至少将部分分离为命名方法,以便更清楚每个部分在做什么。不管是不是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("");
        }
    
    for(int i=0;i
    但我不知道如何使用构造函数,哪些变量应该是私有的

    无论是什么,都应该是
    私有的
    。要确定这一点,通常最简单的方法是将所有内容标记为
    私有的
    ,然后在遇到“痛点”时将其升级为
    公共的

    至于您需要什么类,请查看“气味”的现有代码,例如:

    这里有一个“命名原语”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 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("");
       }
    }
    
    公共类卡{
    私有整数宽度;
    私有整数长度;
    私人int[][]卡;
    公共卡(整数长度、整数宽度){
    这个长度=长度;
    这个。宽度=宽度;
    this.cards=新整数[长度][宽度];
    }
    公开无效洗牌(){
    //现有的洗牌方法在这里使用-但适用于私人卡
    }
    公开作废印刷品(){
    for(int i=0;i
    然后,我们意识到,
    并不是这个好名字……它更像是一个
    ——重命名它,然后转到下一个“命名原语”或2

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


    2很多代码的气味都是OOP代码特有的。要查看您试图转换为OO的过程代码,我认为“原始困扰”、“数据束”、“消息链”和“长参数列表”是最相关的。

    如果要发表评论,我会将您的整个代码粘贴到一个服务中,比如:这样它就不会干扰您的问题。@Anthony:事实上,据我所知,标准做法就是不这样做。您可以将整个代码粘贴到问题末尾,以避免中断问题流程,但当我见过人们在场外粘贴和链接,他们被告知不要这样做。我认为目标是在实际问题和答案方面保持如此独立(因此也不鼓励只链接的答案)。这是一个好问题-首先回顾一下您正在尝试做的事情会有什么帮助。在您的程序代码中添加注释,以便向我们(和您自己)解释你试图完成的。这将有助于制定问题,然后可以在不同的范例中考虑。盲目地将过程移植到对象通常对任何人都没有帮助。我不同意Anthony的观点。代码对问题很重要,出于存档原因,我不会将代码放在单独的网站上。此外,我们有滚动条。我认为已经有了很大的改进
    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("");
       }
    }
    
    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("");
       }
    }
    
    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("");
       }
    }