If any of those objects can be null, then you have to check for null before calling a getter on this object, of course.
But this kind of chaining is a bad smell of a lack of encapsulation (anemic objects having just data, and no behavior). You're violating the law of Demeter : don't talk to strangers.
Answer from JB Nizet on Stack OverflowIf any of those objects can be null, then you have to check for null before calling a getter on this object, of course.
But this kind of chaining is a bad smell of a lack of encapsulation (anemic objects having just data, and no behavior). You're violating the law of Demeter : don't talk to strangers.
You can use Apache Commons BeanUtils to navigate through your nested properties like this:
Add method getSomeString() to your Outer class and write something like
PropertyUtils.getNestedProperty(this, "innerA.innerB.someString");
I can't remember if that PropertyUtils class check null properties, but I would look Apache Commons BeanUtils site.
Hope this helps!
java - OOP Objects, nested objects, and DAO's - Software Engineering Stack Exchange
What are nested objects in OOP concept? (mainly in java) - Stack Overflow
How to declare nested data object in java?
What is the best way to support nested object model in java? - Stack Overflow
Should I be nesting one object as part of another or should I be creating more specific objects for different usages.
Follow OO principles first which means "more specific objects." In doing so your classes may "line up" with your database schema or not but do not let DB schema trump good OO design.
Single Responsibility Principle will help guide you in what classes to build. SRP means, for example, that a
Songis a song. It is not an artist, it is not a list of subscribers, so it should not have artist or subscriber stuff in it. Only song stuff.The above means that you will have lots of small, independent, fully functional things - classes. By "fully functional" I mean, if a
Songis aname,date, andidthen that's what's in it. period. The fact that a certain artist sings that song does not inherently, fundamentally define what aSongis. This means other classes to model relationships like "an artist's song repertoire" for example.Small functional classes leads to good DAO's and flexibility for your user interface.
Option 1 means wasting a lot of time/resources grabbing information I may not need for that page but easier to manage. Option 2 is messy and requires keeping track of which object is what but faster and far less db calls
You are falling victim to premature optimization. How can you know up front that option 2 will have "fewer DB calls?" What does that mean anyway?
This is simply the wrong way to think about your domain classes/model. This is why you end up duplicating your DB schema:
.
Class SongWithArtist {
private $song; //Basic Song object
private $artist; //Basic Artist object
}
When what you should have is something describing the real world:
Class ArtistPortfolio {
private Artist $theArtist;
private List<Song> $portfolio; // list of songs (s)he sings
}
Class ArtistSubscribers {
private Artist $theArtist;
private List<User> $subscribers; // list of people who like this artist
}
// And it would probably make sense to combine the above 2 classes:
Class ArtistProfile {
// an Artist object, not just an id. We're doing OBJECT oriented programming.
private Artist $theArtist;
private List<Song> $portfolio; // list of Song objects
private List<User> $subscribers; // list of User objects
}
// and if you need a list of profiles...
Class ArtistProfiles {
private List<ArtistProfile> $profiles; // a list of type ArtistProfile
public ArtistProfile GetProfileByArtist (Artist thisArtist){}
public ArtistProfile GetProfileByName (string name) {}
public ArtistProfile GetProfileById (string id) {}
}
// I'd say a ArtistProfile could be part of an Artist..
Class Artist {
private $id;
private $name;
private ArtistProfile $profile; // this is composition.
}
//In lieu of the above, an DAO oriented Artist composition ...
// Just go with the refactoring flow!
Class Profile {
private $id;
private $name;
private $birthdate
}
Class Repertoire {
// a Profile object, not just an id. We're doing OBJECT oriented programming.
private Profile $theArtist;
private List<Song> $portfolio; // list of Song objects
private List<User> $subscribers; // list of User objects
}
Class Artist {
private Profile $me;
private Repertoire $myStuff;
}
Too Many DB Calls!
NOT. You can instantiate a Artist object without populating the $myStuff and in turn, defer populating $subscribers / portfolio lists until needed. This is called lazy loading.
I believe that what you want to do when programming in general is to avoid duplicating data.
When designing a relational database, there are 4 types of relationships:
- one-to-one
- one-to-many
- many-to-one
- many-to-many
For a many-to-many relationship, you have a "link table" in a database where usually just has the two IDs of the two records being linked to each other.
In addition to the two linked record IDs, a link table can have any other data associated between the two database tables with the many-to-many link table.
For example,
class DBRecord {
private $recordID; // a BIGINT, auto-incrementing field, the primary key
}
class Product extends DBRecord {
private $productID; // an ID that the user can set
private $productName;
private $suggestedRetail;
...
}
class Vendor extends DBRecord {
private $vendorID; // an ID that the user can set
private $vendorName;
private $contactID;
...
}
class ProductVendors extends DBRecord {
private $productRecordID; // this ID never changes
private $vendorRecordID; // this ID never changes
private $wholesaleCost; // the cost of a product can be different by vendor
}
In this example, objects of the classes: Product, Vendor, and ProductVenders are much like the records that are in the database. You could possibly read an entire database table into an array.
$products = readAll();
$vendors = readAll();
$productVendors = readAll();
Depending upon the size of your dataset in the number of records, you may not want to read them all into RAM.
When you have too many records to read them all into RAM, you can setup your relations between your objects to mirror the relations between your database tables in your relational database:
// database code is encapsulated in this class
class DB {
...
}
// this class implements functionality common to all subclasses
abstract class DBTable {
private $db;
private $internalName; // the SQL name for this database table
private $displayName; // the name that the user sees for this db table
public lookup($productID) {
...
}
}
class Products extends DBTable {
...
}
class Vendors extends DBTable {
...
}
class ProductVendors extends DBTable {
...
}
That's how I've done many-to-many relationships, and it works even for very large datasets such as maybe having 100,000 product record.
One-to-many and many-to-one are just the flip-side of each other
class PurchaseOrderLineItem extends DBRecord { } class PurchaseOrder extends DBRecord { private $lineItems; public loadLineItems() { ... } public saveLineItems() { ... } }
A line-item of a purchase order can only be on one purchase order document, but a purchase order document can have many line items on it. This generally isn't a huge number of line-items, so I just load them all into RAM, into an array.
One-to-one relationships
class Product extends DBRecord { private $itemRecordID; private $inventoryOnHand; ... } class InventoryCount extends DBRecord { private $itemRecordID; private $inventoryCounted; }
These two records are a one-to-one relationship. When counting all of the inventory in a store, for each product there is only one count, and for each count, there is only one product.
So, those are the four types of relationships. I think that the most general solution is to mirror your relational database, but I don't always do that such as in the case of purchase orders which "contain" their line-items.
Watch out for multi-user problems The famous lost-update problem.
Don't duplicate data See "Normal forms".
Store date-of-birth -- not age Generally it's best to not store an age, but a date-of-birth and have an accessor called "getAge()" to calculate and return an age.
You will need recursion. Iterate over all the persons in the List and search within that person for the same target. Once you found your target, return and stop all searching.
Here is some pseudo code:
Person search(Person, Name)
if (Person.Name == Name) return Person;
for each subPerson in Person.person:
Person found = subPerson.search(Person, Name);
if (found != null) return found;
return null;
You are going to need to visit every person, and every person each person holds, this is easily implemented using a recursive algorithm, which is therefore depth first.
One thing to consider: do you know that names are unique? If not you'll need to return a list of matching Persons, and that might be mopre appropriate if you want to do, say, a pattern match on the name: all people whose surname is "Smith"
As you've described it (with each box containing a max of 1 box) what you have is effectively a linked list. You don't need recursion for that, just walk the list keeping the current box in a variable.
But possibly what you're trying to solve for (where a box can contain multiple boxes) is a tree, and what you need is a search function for that tree. Without knowing anything of the expected node distribution in your tree, I would highly recommend doing a DFS (https://en.wikipedia.org/wiki/Depth-first_search), as this is easy to implement and is performant on a broad array of tree types.
One way is to hold a reference to the most out box.
class Box{
private Box nestedBox;
public Box(){
}
public Box(Box nestedBox){
this.nestedBox = nestedBox;
}
}
public class Main {
public static void main(String[] args) {
int numOfBoxes = 4;
Box nestedBox = null;
for(int i = 0; i < numOfBoxes; i++){
nestedBox = new Box(nestedBox);
}
}
}