Should objects know about their users in certain cases? - encapsulation

I'm laying out the foundations for a potential game, but I'm having trouble designing the classes to be encapsulated yet efficient.
Generally, people say objects should rely little on each other to preserve modularity and encapsulation.
However, sometimes it seems convenient to have some object know about each other.
Let's say we have a class called Dog.
public class Dog {
public void eat() { ... }
public void wagTail() { ... }
}
Dogs have owners, so there is a dog owner class.
public class DogOwner {
private Dog dog;
public Dog getDog() { return dog; }
public void petDog() { ... }
public void takeDogForWalk() { ... }
}
Now, what if we have a Dog, but we don't have its owner? It seems to make sense to make a getOwner() method for Dog.
public class Dog {
private DogOwner owner;
public void eat() { ... }
public void wagTail() { ... }
public DogOwner getOwner() { return owner; }
}
However, this now gives Dog information about the DogOwner, which seems to violate information hiding. It also seems to create redundancy, because Dog has a DogOwner, and DogOwner has a Dog.
Another way to find the owner is to simply look through all the owners, and find the corresponding dog. Though this will not create dependency of Dog and DogOwner, this seems a lot more expensive than it needs to be, because we have to cycle through all the owners.
So, is it alright for Dog to have a getOwner() method? If it is not, what other alternatives are there to efficiently access the owner if only the Dog is known?

"Should rely little" - just as much as is needed, not more, not less.
Of course the dog can have a link to its owner. You asked about the alternatives: One, to always carry the dog and the owner information together, even when lots of code doesn't care about the owner. Two, if you have a dog and don't know the owner, you obviously can't ask the owner. You could have a hash table mapping dogs to owners, but then you might as well just store the dog with the owner. Or you have a database of all dog owners and scan it for an owner of that dog - not exactly scaleable.

While I'm not a software design pragmatist, I don't see how this would necessarily violate too many design principles. For Dog to "know" anything about DogOwner it still needs to access DogOwner's methods. So, you're not saying Dog.getDogOwnersName or something like that, you would say Dog.getOwner().getName(). This way, all Dog cares about is who its owner is. But any information beyond that is effectively still hidden.

I would say it's alright to do this. One alternative that comes to mind though would be to use a dictionary with Dog as the key and DogOwner as the value (since hypothetically the DogOwner could change over time). This would also have an added benefit of keeping one central repository of Dog/DogOwner relationships.

Related

I'm learning about object oriented concepts in Apex Code and I keep on getting a "Variable does not exist: name " . What am I doing wrong?

I created a class first:I'm learning about object oriented concepts in Apex Code and I keep on getting a "Variable does not exist: name " . What am I doing wrong?
public class Dog
{
public String name;
public integer age;
public void disp()
{
system.debug('Name of my dog '+name);
system.debug('Age of my dog '+age);
}
}
My Apex Code:
Dog d1=new Dog();
d1.name='scooby';
d1.age=12;
d1.disp();
Dog d2=new Dog();
d2.name='tiger';
d2.age=13;
d2.disp();
Your code compiles and runs just fine.
Are you sure you saved changes to the Dog class OK? No compile errors? Perhaps your old version had typo in name or maybe that field wasn't marked public?
Perhaps you already have another class called Dog in this org?

How to unindex lists in Objectify?

Why is it not possible to unindex a list of an objectify entity?
To demonstrate the problem I made a simple example project.
I used the entity
#Entity
public class Car {
#Id String id;
#Unindex List<Passenger> passengers;
}
an the object
public class Passenger {
String name;
}
and saved it using this simple method.
public class CarFactory {
public void writeCarEntity() {
Car car = new Car();
car.setId("myCar");
List<Passenger> passengers = new LinkedList<Passenger>();
Passenger carl = new Passenger();
carl.setName("Carl");
Passenger pete = new Passenger();
pete.setName("Pete");
Passenger jeff = new Passenger();
jeff.setName("Jeff");
passengers.add(carl);
passengers.add(pete);
passengers.add(jeff);
car.setPassengers(passengers);
ObjectifyService.register(car.getClass());
ObjectifyService.ofy().save().entity(car).now();
}
}
Looking up the entity in the datastore you get this information:
Although the passengers field has the annotation #Unindex it will be indexed, as one can see in the google "Datastore". Why does the annotation #Unindex has no effect in this example???
This is unrelated to Objectify and appears to be some new quirk of the datastore. It might just be a display glitch in the UI. Is it causing problems?
With the code you posted, Objectify will call Entity.saveUnindexedProperty() on the passengers field (even without the #Unindex annotation). But even if Objectify tried to index it, historically you can't index embedded objects, so it's unclear what it means to index a list of them. Maybe Google is rolling out some new behavior and they haven't got the GUI working correctly yet? Or maybe there is a bug in their save behavior?
If you want to be a good citizen, create a simple test case with the low level API (an Entity that contains a property of type List<EmbeddedEntity>), verify that this same behavior occurs, and file a bug in the GAE issue tracker.

Simple Framework with Getters and Setters in Android

I'm new to Simple Framework, but I didn't find any advice about the use of the Getters/Setters knowing that they are not good in Android for performance point of view.
http://developer.android.com/training/articles/perf-tips.html#GettersSetters
Is there a way to not use them in Simple-Framework ?
My answer will probably be better with code samples, but pretty much. Whenever you are dealing with the field within the class, try to use the actual variable vs a method.
example. Within your class, you would use it like the following:
public class Foo
{
public Object bar; // This would be private if I was using a getter
public void doSomeStuff()
{
if(bar)
{
//work the bar
}
}
public Object getBar()
{
return bar;
}
}
Then externally, it would be used like this:
public class OtherFoo
{
public void somethingElse()
{
Foo ob = new Foo();
inner = ob.getBar();
}
}
External getters are a pro/con here, as they do break the performance rule stated, but they promote much better practices (preserved encapsulation, less nasty coupling, better maintainability, etc).
This all being said though, this performance tip can be taken with a grain of salt, since Android devices have gotten more and more powerful (in fact, I'm very certain this performance hit has almost been removed as of GingerBread).
My personal recommendation is to follow OOP principle, and use getters when possible, unless there is a serious performance issue.

Design pattern to process different file types in OOP

I need to process a big set of files that at the moment are all loaded into memory on a List.
i.e:
List(FileClass) Files;
Use:
Reader.Files; //List of files of the type
File Class has one attribute to match each FileInfo object property i.e: Name,CreateDate,etc.
Also has a List of Lines of the type (LineNumber, Data).
Now I need to create an logic to interpret these files. They all have different logic interpreteations and they will be loaded on to their correspondent Business Object.
i.e:
Model model = new Model()
.emp => Process => Employee Class
.ord => Process => Order Class
model.AddObject(emp);
model.AddObject(ord);
My question what is the best design pattern for a problem of this sort.
All I can think of is... something like this:
public ProcessFiles(List<Files> Files)
{
Model model = new Model()
var obj;
foreach(file in Files)
{
switch (File.GetExtension(file))
{
case "emp":
obj = BuildEmployee(file) //returns Employee class type
break;
case "ord":
obj = BuildOrder(file) //returns Order class type
break;
}
model.AddObject(obj);
}
}
Is there a better way to approach this?
This solution looks procedural to me, is there a better Object Oriented Approach to it?
Cheers
UPDATE:
I've come across a few options to solve this:
1)- Use of Partial classes for separation of concerns.
I have a data model that I don't want to mix File processing, Database use, etc (Single Responsibility)
DATA MODEL:
public partial class Employee
{
public int EmployeeID;
public string FirstName;
public string LastName;
public decimal Salary;
}
INTERPRETER/FILE PARSER:
This partial class defines the logic to parse .emp files.
// This portion of the partial class to separate Data Model
from File processing
public partial class Employee
{
public void ProcessFile(string FileName)
{
//Do processing
}
...
}
Intepreter Object
public class Interpreter : IInterpreter
{
foreach(file in Files)
{
switch (fileExtension)
{
case .emp
Employee obj= new Employee();
case .ord
Order obj = new Order(file);
}
obj.ProcessFile(File)
Model.AddObject(emp)
}
}
2)- Perhaps using some sort of Factory Pattern...
The input is the file with an extension type.
This drives the type of object to be created (i.e: Employee, Order, anything) and also the logic to parse this file. Any ideas?
Well, it seems that you want to vary the processing behaviour based on the file type. Behaviour and Type being keywords. Does any behavioural pattern suit your requirement?
Or is it that the object creation is driven by the input file type? Then creation and type become important keywords.
You might want to take a look at strategy and factory method patterns.
Here is something from the book Refactoring to Patterns:
The overuse of patterns tends to result from being patterns happy. We
are patterns happy when we become so enamored of patterns that we
simply must use them in our code. A patterns-happy programmer may work
hard to use patterns on a system just to get the experience of
implementing them or maybe to gain a reputation for writing really
good, complex code.
A programmer named Jason Tiscione, writing on SlashDot (see
http://developers.slashdot.org/comments.pl?sid=33602&cid=3636102),
perfectly caricatured patterns-happy code with the following version
of Hello World. ..... It is perhaps impossible to avoid being patterns
happy on the road to learning patterns. In fact, most of us learn by
making mistakes. I've been patterns happy on more than one occasion.
The true joy of patterns comes from using them wisely.

Playframework Siena Filtering and Ordering

This is my first question on any of these websites so pardon my unprofessionalism.
I use playframework with SIENA module (with GAE) and I came accross the following problem:
Given 3 entities:
public class Meeting extends Model{
#Id
public Long id;
public String place;
#Owned
Many<MeetingUser> users;
.
.
.
}
public class User extends Model{
#Id
public Long id;
public String firstName;
public String lastName;
#Owned
Many<MeetingUser> meetings;
.
.
.
}
public class MeetingUser extends Model{
#Id
public Long id;
public Meeting meeting;
public User user;
.
.
.
public User getUser(){
return Model.all(User.class).filter("id", user).get();
}
public Meeting getMeeting(){
return Model.all(Meeting.class).filter("id", meeting).get();
}
}
For instance I am listing a meeting and all their users:
public static void meetingInfo(Long meetingId){
Meeting meeting = Models.all(Meeting.class).filter("id",meetingId);
List<MeetingUser> meetingusers = meeting.asList();
List<User> users = new ArrayList<User>();
for(MeetingUser mu: meetingusers){
users.add(mu.getUser());
}
render(users);
}
This is done(is there any better way here?) however when it comes to filtering (especially dynamic filtering for many many fields) I can not use the Query's filter method on the MeetingUser as I need to filter on a MeetingUser's field's field (firstName). The same problem arise for ordering. I need the solution for both problems.
I hope my problem is clear and I appreciate any kind of help here.
Remember that you are in GAE which is a NoSQL DB.
So you can't do Join request as in RDBMS.
Yet, this is not really the pb you have so this was just to be sure you are aware of it ;)
So if you want to find the person having given firstname in a given meeting, can you try the following:
List<MeetingUser> meetingusers = meeting.users.asQuery().filter("firstname", "XXX");
(you can also order)
Nevertheless, knowing that you can't join, remember that you can't write a query searching for a meeting in which there are users whose firstname is XXX as it would require some joins and it doesn't exist in GAE. In this case, you need to change your model following NoSQL philosophy but this is another subject
regards
Let's try to give a way to do what you want...
Your relation is a Many-to-Many which is always the worst case :)
You want to filter Meeting by User's firstname.
It requires a join request which is not possible in GAE. In this case, you must change your model by denormalizing it (sometimes use redundancy also) and manage the join by yourself. Actually, you must do the job of the RDBMS by yourself. It seems overkill but in fact, it's quite easy. The only drawback is that you must perform several requests to the DB. NoSQL means No Schema (& No Join) so there are a few drawbacks but it allows to scale and to manage huge data load... it depends on your needs :)
The choice you did to create the MeetingUser which is a "joined" table and a kind of denormalization is good in GAE because it allows to manage the join yourself.
Solution:
// fetch users by firstname
List<User> users = users.all().filter("firstName", "John").fetch();
// fetch meetingusers associated to these users (verify the "IN" operator works because I didn't use that for a long time and don't remember if it works with this syntax)
List<MeetingUser> meetingusers = MeetingUser.all().filter("user IN", users);
// now you must fetch the whole meeting because in MeetingUser, only the Meeting ID is stored (other fields are Null or O)
List<Meeting> meetings = new ArrayList<Meeting>()
for(MeetingUsers mu:meetingusers) {
meetings.add(meetingusers.meeting);
}
// use the batch feature to fetch all objects
Meeting.batch(Meeting.class).get(meetings);
// you have your meetings
Hope this helps!

Resources