简体   繁体   中英

Avoid type casting

I have an empty interface called Data which is implemented by classes DataOne and DataTwo .

I then have a class called DataHolder which contains a Data object.

It looks something like this:

public class DataHolder() {
    public Data data;
}

public class DataOne() {
    public int importantData;

    public int getImportantData() {
        return importantData;
    }

    public int setImportantData(int importantData) {
        this.importantData = importantData;
    }
}

public class DataTwo() {
    public int notSoImportantData;
}

Let's say theres a function which takes a DataHolder object and does some operation on the importantData integer.

public void calculateImportantData(DataHolder dh) {
    int importantData = 1234567890;
    dh.data.setImportantData(importantData);
}

How can I be sure that the DataHolder contains a DataOne object, without typecasting?

How about:

public class DataHolder<T extends Data> {
    public T data;
}

and in your code you will have:

public void calculateImportantData(DataHolder<DataOne> dh) {
   int importantData = 1234567890;
   dh.data.setImportantData(importantData);
}

and I assume you meant DataOne and DataTwo to implement Data.

first of all , I tweaked your code a little bit ,

1- I created an Interface , Data , containing some random method someMethod() :

package main.interfaces;

public interface Data {

  int myData = 0;

   public void someMethod();
}

2- then , I created 2 classes called DataOne and DataTwo : Class DataOne: ( notice how i added the important business method setImportantData() here , this provides total Encapsulation of your work).

package main;
import main.interfaces.Data;
public class DataOne implements Data{
    public int importantData;

    public int getImportantData() {
       return importantData;
    }

    public void setImportantData(int importantData) {
       this.importantData = importantData;
    }

    @Override
    public void someMethod() {
       System.out.println("here in DataOne!... ");

    }
    public void calculateImportantData(int importantData) {

    //      int importantData = 1234567890;

       setImportantData(importantData);
    }

}

Class DataTwo:

package main;

import main.interfaces.Data;

public class DataTwo implements Data{
public int notSoImportantData;

@Override
public void someMethod() {
    System.out.println("here in DataTwo!...");

}
public void calculateUsualData(DataTwo d2) {
    d2.someMethod();

}

}

after that , using Factory Design Pattern ... I created this DataFactory class:

package main.factory;

import main.DataOne;
import main.DataTwo;
import main.interfaces.Data;

public class DataFactory {
    public static Data getData(String dataType){
          if(dataType == null){
             return null;
          }     
          if(dataType.equalsIgnoreCase("DATAONE")){
             return new DataOne();
          } else if(dataType.equalsIgnoreCase("DATATWO")){
             return new DataTwo();
          } 
          return null;
       }

}

now , back to your problem solution , I used DataHolder , encapsulating DataFactory here:

package main.holder;

import main.factory.DataFactory;
import main.interfaces.Data;

public class DataHolder {
    Data data;
    public DataHolder(String dataType){
        data = DataFactory.getData(dataType);
    }

    public Data getData(){
        return data;
    }
}

now , try to run the application , I added some comments that will appear on your console , and I hope they will be helpful :)

package main.run;

import main.DataOne;
import main.DataTwo;
import main.holder.DataHolder;
import main.interfaces.Data;

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

        // lets assume user of the method passed a DataOne Object, you can
        // manage it by changing the value of flag string
        String flag = "DataOne";
        DataHolder dataHolder = new DataHolder(flag);

        if (dataHolder.getData() instanceof DataOne) {
            System.out
                    .println("you have a DataOne object , but a Data reference");
            System.out
                    .println("/nso , you need to create a 'reference' to DataOne to work on that object ...");
        } else if (dataHolder.getData() instanceof DataTwo) {
            System.out
                    .println("you have a DataTwo object , but a Data reference");
        } else {
            System.out
                    .println("you dont have a DataOne nor DataTwo references , it is a "
                            + dataHolder.getData().getClass() + " object!");
        }

        System.out
                .println("in order for the compiler to pass the following test , you must cast he RHS ( right hand side ) to match the LHS (left hand side)");
        // in order for the compiler to pass the following test , you must cast
        // the RHS ( right hand side ) to match the LHS (left hand side)
        DataOne d1 = (DataOne) dataHolder.getData();
        // in case you wanted to test DataTwo scenario
        //DataTwo d2 = (DataTwo) dataHolder.getData();

        System.out.println("if you didnt do that , you can make it a Data Object , but you will not be able to access the method 'getImportantData()' created in DataOne");
        Data data =  dataHolder.getData();
    }

}

(note , here the program structure is : you select the type of the data before you start the application , stored in the "flag" variable inside the main method. after that , a call to DataHolder method will be made , after that , you can check the returned object and check if it is what u specified earlier. if you want it to be a little complicated , you can pass the object type in the DataHolder's constructor , and do the check from there , I didn't want to do it just for simplicity. Good Luck)

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