简体   繁体   中英

How to better randomize method calls in Java (without repeating similar lines)?

I have this file as an example of a Pet app for Android that showcases profiles of cats or dogs (courtesy of a Udemy course). this is the base file:

package com.delta.generics;

import android.app.Activity;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Bundle;
import android.service.dreams.DreamService;
import android.util.StringBuilderPrinter;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class GenericsActivity extends Activity {

    public TextView nameTextView = null;
    public TextView descriptionTextView = null;
    public RatingBar ratingView = null;
    public ImageView portraitView = null;
    public Button nextButton = null;

    private int currentSelection = 0;

//    CatAdapter catAdapter;
    AdoptAdapter<Cat> catAdoptAdapter;
//    AdoptAdapter<Dog> dogAdoptAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_generics);

        nameTextView = (TextView) findViewById(R.id.nameTextView);
        descriptionTextView = (TextView) findViewById(R.id.descriptionTextView);
        ratingView = (RatingBar) findViewById(R.id.ratingView);
        portraitView = (ImageView) findViewById(R.id.portraitView);
        nextButton = (Button) findViewById(R.id.nextButton);
        nextButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showNext();
            }
        });

//        commenting this out in favour of AdoptAdapter objects
//        catAdapter = new CatAdapter(this,nameTextView,descriptionTextView,ratingView,portraitView);
//        catAdapter.set(AdoptData.mCatList.get(0));

        catAdoptAdapter = new AdoptAdapter<Cat>(this, nameTextView, descriptionTextView, ratingView, portraitView);
//        dogAdoptAdapter = new AdoptAdapter<Dog>(this, nameTextView, descriptionTextView, ratingView, portraitView);

        catAdoptAdapter.set(AdoptData.mCatList.get(0));
//        dogAdoptAdapter.set(AdoptData.mDogList.get(0));
        // mCatList and mDogList is an object already exists in AdoptData.java

    }

    public void showNext(){
        int random = currentSelection;
        int animal_random = 0;
        animal_random = (int )(Math.random() * 2;
        while(random == currentSelection){
            //avoid same selection twice.
            random = (int )(Math.random() * AdoptData.mCatList.size());
            random = (int )(Math.random() * AdoptData.mDogList.size());
        }
        currentSelection = random;
        Cat c = AdoptData.mCatList.get(random);
//        Dog d = AdoptData.mDogList.get(random);
//        commenting in favour of AdoptAdapter object
//        catAdapter.set(c);
        catAdoptAdapter.set(c);
//        dogAdoptAdapter.set(d);
        
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.generics, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }



}

在此处输入图像描述

The issue I see is that the way this is formatted, it can only either showcase Cat or Dog profiles, but not together, and I wanted to figure out a way of how to "mix" them so both Cats and Dogs shows up randomly when pressing the "Next" button. And so I figured within the context of Java and this file, I figured I can modify the showNext() method:

    public void showNext(){
        int random = currentSelection;
        int animal_random = 0;
        animal_random = (int )(Math.random() * 2);
        Log.e("animal_random", String.valueOf(animal_random));
        switch(animal_random){
            case 0:
                while(random == currentSelection){
                    //avoid same selection twice.
                    random = (int )(Math.random() * AdoptData.mCatList.size());
                }
                currentSelection = random;
                Cat c = AdoptData.mCatList.get(random);
                catAdoptAdapter.set(c);
                break;
            case 1:
                while(random == currentSelection){
                    //avoid same selection twice.
                    random = (int )(Math.random() * AdoptData.mDogList.size());
                }
                currentSelection = random;
                Dog d = AdoptData.mDogList.get(random);
                dogAdoptAdapter.set(d);
                break;

        }
    }

But I feel like there are way too many "repeated lines" here. If this were in Python I would probably utilize the getAttribute() method to determine which method to use in the object based on a string match. However when I tried to use the supposed Java equivalent getMethod() i keep getting a java.lang.NoSuchMethodException error when i try to use it.

Is there a better way to go about this in Java...? Or would it require a complete restructure for this specific example?

Once you've picked any of the two alternatives below, just update the rest of your code and you'll probably see less duplication across the board since the animals will have a common ground somewhere. :-)

The interface way

Create an Animal interface that gives you access to the common things for animals in your given case, and then implement the interface in both your Dog and your Cat class. Your code in question will probably mostly be talking about Animal s instead, unless you explictly need to differentiate between a Dog or a Cat in some way.

One of the neat things about this approach is that while the interface will enforce a contract, it also gives you the wiggle room for if you example want the Dog class to be able to contain stuff that the Cat shouldn't. Maybe it already does?

The enum way

Consolidate your Dog and Cat classes into a single Animal class that carries an enum field called type or something like that. Less classes (hurray?), but with the caveat that the dogs, cats and whatever future animals you add kinda have to fit into the same data structure. Depending on how much weight and meaning the actual type of animal actually has, this may or may not be a really bad idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM