Decoupling - OOP - java

I have a simple question (working with Java). I have two classes, one represents a Document, a second represents a Word.
The Document class needs to know some info about the words that is kept in Word. My question is, what's the best way to decouple the two classes? I have 2 options in mind:
Have no connection between the classes, and each time I call a method in Document, I pass it an object of Word (so I have a third class with a main method that initiates
both Document and Word).
Declare a private object of Word inside Document.
One thing to note, I only have one object for Word and one for Document. I don't create a new object for every new document or word. I store a list of the entire documents in Document, and a list pf the entire words in Word.
Thanks!

I don't agree with your understanding of Decoupling. Decoupling is not just about which objects create other objects, it's also about which objects know about the behaviour of other objects and (crucially) what needs to change in (your example) Document if Word changes.
However, also I really don't understand what your mean by these two phrases:
I only have one object for Word and
one for Document. I don't create a new
object for every new document or word.
I store a list of the entire documents
in Document, and a list pf the entire
words in Word
Start from Document. What can objects of this class do? You seem to be saying that
class Document {
private List<??OfWhat??> allDocuments;
}
If class Document contains a List, what's it a List of? I think you need:
class Shelf {
private List<Document> allDocuments;
}
class Document{
private List<Word> wordInOneDocument;
}
class Word {
private String wordContents;
}
Now a Shelf could offer methods such as getRecentDocumets() findDocumentsContaining(String text)
and Document could contain getWordCount() and insertParagraph(List, START); and so on.
To have a better discussion we need to see a bit more of what you had in mind, a bit more about behaviour.
I do agree with your general thought that there is Something other than Document and Word out there. Something that can reasonably invoke methods such as createDocument() and insertParagraph()

From my point of view...
public class Document{
private List<Word> words = new ArrayList<Word>();
public void setWord(ArrayList<Word> words){this.words = words;}
public ArrayList<Word> getWord(return this.words;)
}
It's a reasonable approach. In this example you can create a Document without any Word's, which makes for an empty Document, which is valid.
You could still create a third class as you suggest, however, I don't see the benefit with it.

Your problem should be solved by composition. Thus having a List of Word seems to be a valid approach. By separating out Documents and Words, you have already achieved the required de-coupling. I do not get your exact point of de-coupling Document and Word objects.

Your question is
what's the best way to decouple the two classes? I have 2 options in mind:
Neither option satisfies your request. If they are going to work together, then they are going to be coupled. The only thing is how tight or loose the coupling is.
Both of your options sound like tight coupling. A form of looser coupling would be to store an interface reference and take it in on a constructor or setter method.

If you want to decouple the classes, one standard way is to use an interface:
public interface IWord {
...
}
public class Word implements IWord {
...
}
public class Document {
public boolean append(IWord word) { ... }
...
}
This way both Class and Word depend on IWord, but neither class nor Word depends on the other. This is known as Dependency Inversion.

Well first of all I think you're naming your classes incorrectly.
I don't create a new object for every new document or word. I store a list of the entire documents in Document, and a list pf the entire words in Word.
Judging by what you said here you have something like this:
public class Words {
private List<Word> = new ArrayList<Word>;
// getters+setters
}
public class Documents {
private List<Document> = new ArrayList<Document>;
// getters+setters
}
And you want to use the Words class in the Documents. If you want to do that, that means you can't decouple it (as it's against the very definition of the word "decouple"). I'm guessing here again, but I think you want to code it so you can change the implementation of the Documents class so in the future it could use another class like for example BetterWords.
In order to do that I would create either an abstract class or an interface (depending on the rest of your architecture) and then make the Words class either extend it or implement. Then you can do something like this:
public class Documents {
private List<Document> = new ArrayList<Document>;
private IWords wordsInterface = new Words(); //in case you want to make an interface
private AbstractWords wordsAbstract = new Words(); //in case you want to make an abstract class
// getters+setters
}
Or you can put it in the Document class (the words), don't really know where you want them.

Related

How to convert ArrayList to ExampleSet in Rapidminer?

I'm creating an extension for rapidminer using java. I have an array of elements of type Example and I need to covert it to a dataset of type ExampleSet.
Rapidminer's ExampleSet definition looks like this:
public interface ExampleSet extends ResultObject, Cloneable, Iterable<Example>
I need to pick certain elements from dataset and send it back, still as ExampleSet, however casting is not working and I can't simply create new ExampleSet object since it's an interface.
private ExampleSet generateSet(ExampleSet dataset){
List<Example> list = new ArrayList<Example>();
// pick elements from sent dataset and add them to newly created list above
return (ExampleSet)list;
}
You will need more than a simple explicit cast.
In RapidMiner, an ExampleSet is not just a collection of Example. It contains more complex information and logic.
Therefore, you need another approach to work with ExampleSets. Like you already said, it is just the interface, which lead us to choice of the right subtype.
For starters, (Since: 7.3) simply use one of ExampleSets class's methods .
You also need to define each Attribute this ExampleSet is going to have, namely the columns.
Below, I create one with a single Attribute called First
Attribute attributeFirst = AttributeFactory.createAttribute("First", Ontology.POLYNOMINAL);
ExampleSetBuilder builder = ExampleSets.from(attributeFirst);
builder.addDataRow(example.getDataRow());
ExampleSet result = builder.build();
You can also get the Attributes in a more generic way using:
Attribute[] attributes = example.getAttributes().createRegularAttributeArray();
ExampleSetBuilder builder = ExampleSets.from(attributes);
...
If you have many cases where you have to create or alter ExampleSet, I encourage you to write your own ExampleSetBuilder since the original implementation have many drawbacks.
You can also try searching for other extensions, which may already meet your requirements, and you do not need to create one of your own (belive me, it's not Headache-free).
the ExampleSet class is getting deprecated (but still perfectly fine to use).
You might want to consider switching over to the newer data set API called Belt (https://github.com/rapidminer/belt). It's faster and more intuitive to use. It's still actively developed, so feedback is also welcome.
Also if you have more specific questions, feel free to drop by the RapidMiner community (https://community.rapidminer.com/), where also many of the developers are very active.

Multiple lists or list and getSublist() (Java)

I have an abstract class 'entity' and Objects (that extend 'entity') that implement different interfaces.
I also have an ArrayList that contain all those different Objects.
Now if I need access to all entities that implement a certain interface (to use its methods), I use the following method (which returns a filtered list of 'entities' that implement interface 'IDirectFire'):
public ArrayList<IDirectFire> getDirectFireSublist() {//direct fire sublist
ArrayList<IDirectFire> sublist = new ArrayList();
entities.stream().filter((it) -> (it instanceof IDirectFire)).forEach((it) -> {
sublist.add((IDirectFire) it);
});
return sublist;
}
Now to my question:
Should I further work with this method or should I create a new ArrayList that exists besides 'entities' and that I would need to manually update every time 'entities' changes?
I need to update 'entities' a lot so I'm not sure if it's more efficient to store multiple sublists and update them all every time 'entities' changes or if I should keep using methods to filter 'entities' and apply methods to those sublists. Keep in mind that those sublists would also be used in a loop in other methods e.g.:
private void resetFirestatusIDF() {//reset firestatus (IDirectFire)
getDirectFireSublist().stream().forEach((it) -> {
it.dfHasFired(false);
});}
Is this viable?
Thanks in advance!
Now to my question: Should I further work with this method or should I create a new ArrayList that exists besides 'entities' and that I would need to manually update every time 'entities' changes?
For which reason do you want duplicate the 'entites' data ?
1) You can put them only in a dedicated list. In this case, you don't need getDirectFireSublist() anylonger.
2) You can share them between the two lists without duplicating them.
In this case, you must update the added and the removed entity element because only the modified elements will be updated. But it is rather straight to implement.
If all you need is to loop over a subset of your items, creating a new list is wasteful. Just return the filtered Stream.
public Stream<IDirectFire> getDirectFire() {
return entities.stream().filter((it) -> (it instanceof IDirectFire));
}
You could also use Guava and return a filtered Iterable instead:
public Iterable<IDirectFire> getDirectFire() {
return FluentIterable.from(entities).filter(IDirectFire.class);
}
Then, to loop over the items elswhere:
private void resetFirestatusIDF() {
getDirectFire().forEach((it) -> it.dfHasFired(false));
}
It is better to filter them. It will create a more clear and understandable code at a price of negligible performance decrease which unless you are filtering milliards of elements should be negligible.
The second thing I have noticed is you stream usage for code fragment 1. I would recommend you and alternative approach to it :
> public ArrayList<IDirectFire> getDirectFireSublist() {
> return entities.stream().filter((it) -> (it instanceof IDirectFire)).collect(Collectors.toList());
> }
wakjah mentions in a comment that instanceof is a bit of a design smell. With that in mind, one alternative solution would be to use a Visitor pattern.
public abstract class Entity {
public abstract void acceptVisitor(EntityVisitor visitor);
...
}
public interface IDirectFire {
default acceptVisitor(EntityVisitor visitor) {
visitor.visit(this);
}
...
}
public class ResetFireStatusVisitor implements EntityVisitor {
public void visit(IDirectFire directFireEntity) {
directFireEntity.dfHasFired(false);
}
}
Then, to loop over the items:
entities.forEach(entity -> entity.acceptVisitor(new ResetFireStatusVisitor()));
The ResetFireStatusVisitor calls dfHasFired(false) on anything that implements IDirectFire. In EntityVisitor you can specify default no-op implementations for the other subtypes of Entity.
I'm not suggesting you do this for simple cases, but for large-scale designs this might be a useful answer to this problem. On the other hand, it might not -- this pattern has its share of design smells too.

Iterate list inside list inside list java

I got a question. Is there a simple solution to iterate over the list that is inside of a list and inside of a list again?
So my point is I have few of lists inside of each other (based on xml unmarshall) and I sometimes do not know how deep is the structure.
Exsample:
class Car{
private List<Door>
}
class Door{
private List<Parts>
}
class Parts{
private List<Some1>
}
}
class Some1{
private List<Some2>
}
So how can iterate from Car to Some2 without knowing if there is a list or is empty in a "good way"? I mean without 5-times nested "for" loops mixed up with another 6 "if's".
DeeV makes a good suggestion about each class iterating over their respective lists.
As a client using the Car class, you may want to get all the Some2s that it contains. If you do this:
car.getDoors().getParts().get...
you expose the internals of the Car class. A much cleaner solution would be to have the following method in the Car class:
public List<Some2> getSome2s()
This way, if the internals of Car change (perhaps using a different Collection type) your client code will not break as long as a list of Some2s is still returned.
There is no easier way than nested for loops. If you want more speed try using different structures like Maps.
First implement composite pattern with your classes after you'll be able to recursive to leafs and aggregate them in a list.

Use objects in Enum (Specifically Place in GWT)

I got an application in GWT that will consist of a listbox with more than 50 items. When selecting one I'll go to the corresponding place.
To avoid hard coded values and to share with the server part, I created an Enum lets call it TableEnum
So Table Enum is composed of a key and a displayName.
Which I then use to fill my combo. Once the selection is done, I got the value and so need to get the Place to go to.
That's why I created a factory that take the value of the selection and return a Place object.
First solution I was about to do is transform my value in TableEnum object et do a switch/case creating the correct associated Place.
But I was also thinking about adding the Place directly as a field of my Enum. This would avoid the switch/case and I would only need to do tableEnum.getPlace().
But I'm not really confident that this can be called a good practice. In my head Enum were simple objects not really knowing what was around them.
Thanks for information
Enums in Java are not just a placeholder for integers, or just some constants (such as some languages). Enums are classes with fixed number of objects, so it is a good practice to give your enums more brain, and always forget about lots of if/else or *switch/case*es.
If each item in the enum is associated to only one place, you can create an abstract method on your enum to get the place.
public enum TableEnum {
FIRST(){
public Place getPlace(){ return new FirstPlace(); }
},
SECOND(){
public Place getPlace(){ return new SecondPlace(); }
};
public abstract Place getPlace();
}
Later, you can access the place like so:
TableEnum t = ...
t.getPlace()
like Danny Kirchmeier's, but maybe less code:
enum Table {
first(Place.place1), second(Place.place2);
Table(Place place) {
this.place = place;
}
final Place place;
}
maybe your place should be an enum?

Array of Strings to an Array of Objects

Maybe there is a method that does this that I don't know about - I doubt it though - but I'm trying to convert an array of strings to an array of Objects. Here is the problem: I'm reading a file in from the command line. The file represents several classes of the following types each with their own data fields. Vehicle is the parent class of all who follow: Vehicle,Car,American Car, Foreign car, Truck, Bicycle.
I have no problem reading the file into a string array. However I need to create objects of all these types and store them in an array of type Vehicle[]. For example a portion of the file looks like this:
Vehicle
Kim Stanley Robinson
2344 court drive
(221)885-7777
stackoverflow#overflow.com
American Car
John Bunyon
1010 binary lane
(221)885-55643
bgt.com
convertable
made in detroit
union plant
Where Class type is the first line followed by, Owner's Name, address, phone number, email address...Each type has fields particular to it. So a foreign car is not made in Detroit. Each of these fields appear on a separate line in the file. So what I've done is read the entire file into a string array. However, I need to find my types in the array of strings,create objects of those types, and store them in a Vehicle array. My main problem is that each data field is on a separate line. How should I approach this problem?
This is java code by the way.
Initially reading the data into a String array is fine. Then you need to loop through that array, and based on the "first line" of each loop ("Vehicle", "American car" etc) you will know how many subsequent elements of the array belong to the same.
Something like this (i'll let you fill in the blanks yourself):
int i = 0;
ArrayList<vehicle> vehicles = new ArrayList();
while (i < data.length)
{
if (data[i].equalsIgnoreCase("vehicle"))
{
Vehicle vehicle = new Vehicle();
vehicle.setOwner(data[++i]);
...
vehicles.add(vehicle);
}
else if (data[i].equalsIgnoreCase("american car"))
{
...
}
i++;
}
question is unclear. Do you want to know how to parse the file and use the words on each line to create a object of it?
pseudo:
Vehicle_ptr myVeh = null;
for each line in file
switch line
{
case vehicle: myVeh = new Vehicle();
case American Car : myVeh = new AmericanCar();
default:
if (line.startswithaninteger && (myVeh != NULL)) myVeh.address = line;
etcetc.
}
Tips: use typeidentifiers in the textfile.for example:
car:americancar
address:12345 bla
etcetc
Or use a serializer
You could read the file as you are doing just now but when you read a string that is a Class type create an instance of the correct Vehicle type. It would appear that you would then know that the next x lines of the file are properties of that particular type so you would read the properties and set them on your Vehicle instance. You then have your Vehicle instance to add to the Vehicle array.
I would use a Factory pattern that creates Adapters. The factory would take the string (Vehicle, American Car) and the adapter would take the string array and current index. The adapter would be responsible to knowing how many indices to read and return the concrete object (or an interface).
IAdapter adapter = AdapterFactory.Create( "American Car" );
Object concreteObject = adapter.Popluate( stringArray, currentIndex );
Now, if you have control over how the data is stored, you might want to look into standard serialization, even JSON, to make processing easier.
It seems to me you need a factory pattern to build your set of vehicle types from the inputs. The factory can look after determining where one car specification starts and another one ends. It'll then determine the set of fields for a car, and determine the car type. It can then call the appropriate constructor, passing in all the related fields.
This means that a constructor of (say) an American car specifies all the fields that it's interested in. A European car constructor would do the same. Each constructor can assert on what it's been given so you don't create any cars incorrectly.
The factory will look after parsing and separating the inputs, and determining what is to be built. Each type of car's constructor looks after info for that car only, and performs the appropriate asserts.
The factory will maintain the list of cars created, and return that list (of America/European/Japanese) upon completion.
In pseudo-code:
whilst(!done) {
fields.add(fieldFromFile);
if (carSpecificationCompleted) {
type = getType(fields);
if (type == 'American') {
car = new AmericanCar(fields);
}
else if (type == 'European') {
car = new EuropeanCar(fields);
}
cars.add(car);
clearStoredFields();
}
}
Do you have control of the file being passed in? If so, might I suggest formatting it using XML and then parsing it using JDOM? It would make your life easier in terms of parsing. For example, you could format all vehicle entries like this:
<node type="vehicle>
<attributes location="detroit" color="red" />
</node>
Or whatever format you come up with. The benefit of this is you can then read in only the vehicles (or whatever you want), or use XPath or some other technology to efficiently get the info you want/need and load it to the proper datatype.
Disregard this advice if you have no control over file formatting.
When you have the choice, change your file format.
You can serialize your object by using xstream. Then you only have to store the complete Java object without checking if some value is existing.
I'd use the Builder pattern here instead of Factory. No big difference but find it a bit easier when the parameters vary like it seems to do in his example.

Categories

Resources