I've used Decorator to create a Dataset
class used to build a Dataset Basic Empty (ConcreteComponent
) and Iris class (ConcreteDecorated
) used to populate it.
Decorator allows a user to add new functionality to an existing object without altering its structure
For example, Iris has a its own way to load and store the data in a dataset structure. I've also added the name features to track the string name of their features.
My purpose is to add more ConcreteDecorator
, like Iris, that they have a own way to load and store file/data and to track the name features. The code runs, but my "doubts" is that a dataset is an empty table (define only the data structure) and the population depends on a concrete decorator that uses it. It seems to me that does not respect the SOLID principles (for example DIP). What do you think about this simple implementation?
Component
public interface Dataset
{
public double Distanza(int i, ArrayList<Double> centroide);
public double getCella(int i, int j);
public void inizializzaTabella();
public void stampaDataset();
public void setColonna( ArrayList<Double> colonnaValori);
public ArrayList<ArrayList<Double>> getTabella();
public int getnFeature(); //ok
public int getnRecord() ;
public void setnFeature(int nFeature);
public void setnRecord(int nRecord);
public void setTabella(int Colonna, Double Valore);
public String getNomeDataset();
public void setNomeDataset(String nomeDataset);
public double[][] toMatrix();
public ArrayList<Integer> getFeatureUsate();
public void setNomiFeature(String[] nomiFeature);
}
Concrete component
public class DatasetConcreto implements Dataset
{
private int nFeature;
private int nRecord;
private ArrayList<Integer> featureUsate; // quelle selezionate
private String nomeDataset;
private String[] nomiFeature;
//public double Tabella [][];
private ArrayList<ArrayList<Double>> Mat;
public double Distanza(int i, ArrayList<Double> centroide)
{
double Sum=0;
for(int j=0; j<nFeature; j++)
Sum+=Math.pow((centroide.get(j) - Mat.get(j).get(i)), 2);
return Math.sqrt(Sum);
}
public double getCella(int i, int j)
{
return Mat.get(j).get(i);
}
public void inizializzaTabella()
{
Mat = new ArrayList<ArrayList<Double>>();
featureUsate = new ArrayList<Integer>();
for(int i=0; i< nFeature; i++)
{
Mat.add(new ArrayList<Double>());
featureUsate.add(i); // uso tutte le feature
}
}
public void stampaDataset()
{
System.out.println("Le feature selezionate sono");
for(int j = 0; j<nFeature; j++)
System.out.println(nomiFeature[j].toString());
for(int i=0; i< nRecord; i++)
{
for(int j=0; j < nFeature; j++)
{
System.out.print( Mat.get(j).get(i)+ " ");
}
System.out.println("\n");
}
}
public ArrayList<Double> getRecord(int indiceRandom)
{
ArrayList<Double> record = new ArrayList<Double>();
for(int i=0; i<nFeature; i++)
record.add( Mat.get(i).get(indiceRandom));
return record;
}
public DatasetConcreto(int nFeature, String Nome)
{
setnFeature(4);
setNomeDataset("Iris.data");
inizializzaTabella();
}
public DatasetConcreto(ArrayList<ArrayList<Double>> MatInput, ArrayList<Integer> featureSelezionate, int nRecord)
{
Mat = new ArrayList<ArrayList<Double>>();
this.featureUsate = new ArrayList<Integer>(featureSelezionate);
this.nRecord = nRecord;
this.setnFeature(featureSelezionate.size());
for(int i=0; i<featureSelezionate.size(); i++)
setColonna( MatInput.get( featureSelezionate.get(i)));
}
public DatasetConcreto() {
}
public void setColonna( ArrayList<Double> colonnaValori)
{
this.Mat.add(colonnaValori);
}
public ArrayList<ArrayList<Double>> getTabella()
{
return this.Mat;
}
public int getnFeature() {
return this.nFeature;
}
public int getnRecord() {
return this.nRecord;
}
public void setnFeature(int nFeature)
{
this.nFeature = nFeature;
return;
}
public void setnRecord(int nRecord) {
this.nRecord=nRecord;
return;
}
public void setTabella(int Colonna, Double Valore)
{
Mat.get(Colonna).add(Valore);
}
public String getNomeDataset() {
return this.nomeDataset;
}
public void setNomeDataset(String nomeDataset) {
this.nomeDataset = new String(nomeDataset);
}
public double[][] toMatrix()
{
double[][] matrix = new double[this.getnRecord()][this.getnFeature()];
for(int i=0; i< nRecord; i++)
{
for(int j=0; j < nFeature; j++)
{
matrix[i][j] = Mat.get(j).get(i);
}
}
return matrix;
}
public ArrayList<Integer> getFeatureUsate()
{return this.featureUsate;}
@Override
public void setNomiFeature(String[] nomifeature)
{
this.nomiFeature = new String[nFeature];
this.nomiFeature = nomifeature;
}
}
Decorator
public abstract class DatasetDecorator implements Dataset {
protected Dataset dataset;
public DatasetDecorator(Dataset dataset){
this.dataset=dataset;
}
@Override
public double Distanza(int i, ArrayList<Double> centroide) {
return this.dataset.Distanza(i, centroide);
}
@Override
public double getCella(int i, int j) {
return this.dataset.getCella(i, j);
}
@Override
public void inizializzaTabella() {
this.dataset.inizializzaTabella();
}
@Override
public void stampaDataset() {
this.dataset.stampaDataset();
}
@Override
public void setColonna(ArrayList<Double> colonnaValori) {
this.dataset.setColonna(colonnaValori);
}
@Override
public ArrayList<ArrayList<Double>> getTabella() {
return this.dataset.getTabella();
}
@Override
public int getnFeature() {
return this.dataset.getnFeature();
}
@Override
public int getnRecord() {
return this.dataset.getnRecord();
}
@Override
public void setnFeature(int nFeature) {
this.dataset.setnFeature(nFeature);
}
@Override
public void setnRecord(int nRecord) {
this.dataset.setnRecord(nRecord);
}
@Override
public void setTabella(int Colonna, Double Valore) {
this.dataset.setTabella(Colonna, Valore);
}
@Override
public String getNomeDataset() {
return this.dataset.getNomeDataset();
}
@Override
public void setNomeDataset(String nomeDataset) {
this.dataset.setNomeDataset(nomeDataset);
}
@Override
public double[][] toMatrix() {
return this.dataset.toMatrix();
}
@Override
public ArrayList<Integer> getFeatureUsate() {
return this.dataset.getFeatureUsate();
}
public void setNomiFeature(String[] nomifeature)
{this.dataset.setNomiFeature(nomifeature);}
}
Concrete decorator
public class Iris extends DatasetDecorator
{
private final String[] nomiFeature = {"LunghezzaSepalo",
"LarghezzaSetalo",
"LunghezzaPetalo",
"LarghezzaPetalo"};
public Iris(String NomeFile, Dataset dataset) throws IOException
{
super(dataset);
super.dataset.setnFeature(4);
super.dataset.setNomiFeature(nomiFeature);
super.dataset.inizializzaTabella(); //For init dataset from here
super.dataset.setnRecord( CaricaDataset(NomeFile) );
}
protected int CaricaDataset(String pathFile) throws IOException
{
int iRecord = 0;
BufferedReader bufferLetto = null;
String line = "";
String cvsSplitBy = ",";
try {
bufferLetto = new BufferedReader(new FileReader(pathFile));
while ((line = bufferLetto.readLine()) != null)
{
if (line.length() > 0)
{
String[] cell = line.split(cvsSplitBy);
this.addRow(cell);
iRecord++;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bufferLetto != null) {
try {
bufferLetto.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return iRecord;
}
// new row
public void addRow(Object cell[])
{
System.out.println(this.nomiFeature.length);
for(int i=0; i<this.nomiFeature.length; i++)
super.dataset.setTabella(i, Double.parseDouble(cell[i].toString()));
}
}
Test client
public class Client {
public static void main(String[] args) throws IOException
{
Dataset ds = new DatasetConcreto();
Dataset iris = new Iris("./src/Iris.data", ds);
ds.stampaDataset();
}
}
DatasetConcreto
orDatasetDecorator
are very generic names, typical for examples in a book. They don't tell anything about what the class is, thus I don't believe it's real code because no one would use such names. \$\endgroup\$DataSet
. Instead, create someDataSetReader
and implement what you need there. \$\endgroup\$