Created
September 26, 2012 16:47
-
-
Save KarlHerler/3789121 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package model; | |
import java.util.HashSet; | |
import java.util.Set; | |
/* the documentation did not specify how an album should handle duplicates so I | |
* adopted the iPhoto idea of completely ignoring duplicates. Hence the use of | |
* the Set Collection, rather than i.e. list. | |
* | |
* This method follows the main idea that you shouldn't write methods that you | |
* do not use unless you get paid by SLOC or number of methods. | |
* | |
* A slight bit of introspection, using a separate albums class would make us | |
* able to keep a state for easy finding of active album, but this would make | |
* us lose some simplicity. | |
* | |
* So easy state, and probably better OOP vs simplicity. | |
* | |
*/ | |
public class Album extends SkeletonAlbum { | |
private Album parent; //The parent of this Album | |
private Set<SkeletonAlbum> children; //The child nodes for this Album. | |
/** | |
* The constructor for the Album class takes a name and a parent as input, | |
* the parent can be set to null. | |
* @param n | |
* The name of the album as a string. | |
* @param p | |
* The parent album with the Album type, can also be set to null. | |
*/ | |
public Album(String n, Album p) { | |
assert n != null; //precondition | |
this.photos = new HashSet<Photo>(); | |
setName(n); | |
this.children = new HashSet<SkeletonAlbum>(); | |
this.setParent(p); | |
this.mutable = true; //sets this album to being mutable | |
assert this.getName()==n && invariant(); //postcondition | |
} | |
/** | |
* The constructor for the Album class takes a name and constructs a Album | |
* with that name | |
* @param n | |
* The name of the album as a string. | |
*/ | |
public Album(String n) { | |
assert n != null; //precondition | |
setName(n); | |
this.children = new HashSet<SkeletonAlbum>(); | |
this.photos = new HashSet<Photo>(); | |
this.mutable = true; //sets this album to being mutable | |
assert this.getName()==n && invariant(); //postcondition | |
} | |
/** | |
* Used in tests so can't be private | |
* @return | |
* true if the invariant holds, false other vice | |
*/ | |
public boolean extendedInvariant() { | |
return parent != this/* && | |
!children.contains(this) && | |
children != null*/; | |
} | |
/** | |
* removes this album, in practice by traversing the parent album and | |
* removing the reference to this album. Used outside can't be private | |
* | |
* [27-09-2011 kherler] | |
* Fixed bug where you get a NullPointerException when removing orphan node. | |
*/ | |
public void remove() { | |
if (parent!=null) { parent.removeFromChildren(this); } | |
assert parent==null || !parent.isChild(this) && invariant(); //postcondition | |
} | |
/** | |
* Returns the photos for this album and all the photos of its child albums. | |
* Used by other methods, can't be private | |
* | |
* @return | |
* A set of Photo objects from both this album and its child albums. | |
*/ | |
public Set<Photo> getPhotos() { | |
Set<Photo> returner = new HashSet<Photo>(); | |
returner.addAll(photos); | |
for (SkeletonAlbum child : children) { returner.addAll(child.getPhotos()); } | |
return returner; | |
} | |
/** | |
* Adds a set of photos to album in question. Effectively doing a union of the two sets. | |
* Used by other methods, can't be private | |
* | |
* I allow this set to be empty, since there is no problem. | |
* | |
* @param p | |
* A set containing Photo objects to be added to the album | |
*/ | |
public void addPhotos(Set<Photo> p) { | |
/* I allow the set to be empty because there is no reason that the | |
* set operations should cause a exception or be erroneous when used on | |
* a empty set. | |
*/ | |
assert p!=null; //precondition | |
System.out.println(); | |
photos.addAll(p); | |
assert getPhotos().containsAll(p) && invariant(); //postcondition | |
} | |
/** | |
* Removes a set of photos from the album in question. Effectively removing | |
* the intersection of the two sets from the album set. | |
* Used by other methods, can't be private | |
* | |
* This also works on an empty set. | |
* | |
* @param p | |
* A set containing Photo objects to be removed from the album. | |
*/ | |
public void removePhotos(Set<Photo> p) { | |
/* I allow the set to be empty because there is no reason that the | |
* set operations should cause a exception or be erroneous when used on | |
* a empty set. | |
*/ | |
assert p!=null; //precondition | |
photos.removeAll(p); | |
for (SkeletonAlbum child : children) { child.removePhotos(p); } | |
assert !getPhotos().containsAll(p) && invariant(); //postcondition | |
} | |
/** | |
* Adding a child album to this album, invoked by setParent but could be | |
* invoked by other parties if a "move album" feature was made. | |
* Used by other methods, can't be private (called from setParent to the parent in question) | |
* | |
* @param a | |
* A child album to be added to the set of children. | |
*/ | |
public void addChild(SkeletonAlbum a) { | |
/* I allow the set to be empty because there is no reason that the | |
* set operations should cause a exception or be erroneous when used on | |
* a empty set. | |
*/ | |
assert a!=null && a!=this; //precondition | |
children.add(a); | |
assert children.contains(a) && invariant(); //postcondition | |
} | |
/** | |
* Returns the entire children set. | |
* | |
* (ATM only used for invariants/testing) | |
* | |
* @return | |
* A Set of Album:s with representing all the child albums of this | |
* Album. | |
*/ | |
public Set<SkeletonAlbum> getChildren() { | |
return children; | |
} | |
/** | |
* Removes a set photos from the parent node | |
* @param a | |
* A child Album to be removed from the parent | |
*/ | |
public void removeFromChildren(Album a) { | |
assert a!=null && a!=this; | |
children.remove(a); | |
assert !children.contains(a) && invariant(); | |
} | |
/** | |
* Checks whether a given album is a child of this album. | |
* | |
* This could arguably be private but it's a useful method to interface to | |
* so I see no reason for it to be private. | |
* | |
* @param a | |
* A Album to check if it is a child of this Album | |
* @return | |
* true if the Album a is a child of this Album. | |
*/ | |
public boolean isChild(Album a) { | |
return children.contains(a); | |
} | |
/** | |
* Sets the parent album to this album and add this album to the list of | |
* children for the parent. | |
* Used by other methods, can't be private | |
* @param a | |
* The parent album. | |
*/ | |
public void setParent(Album a) { | |
/* I allow the parent to be null since that is how I define the | |
* root album | |
*/ | |
assert a!=this; //precondition | |
if (a!=null) { | |
parent = a; | |
a.addChild(this); | |
} | |
assert parent==a && invariant(); //postcondition | |
} | |
/** | |
* Fetches the parent of the current object. | |
* | |
* (ONLY USED IN TESTS) <-- can't be private | |
* | |
* @return | |
* The Album that is the parent of this current node. | |
*/ | |
public Album getParent() { | |
return parent; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package model; | |
import java.util.Observable; | |
import java.util.Observer; | |
import java.util.Set; | |
/** | |
* This class implements autogenerated albums based on a given search criteria, | |
* the search criteria can be anything expressed in as boolean expression | |
* (or a series of boolean expressions). | |
* | |
* In order to implement this you need to implement a searchCritera method | |
* which takes a Photo and returns a boolean based on wether or not this photo | |
* should be included in the returned album. | |
* | |
* This class also implements the Observer pattern so using the java.util | |
* version of it, so the album is populated by changes in Photo objects. | |
* | |
* @author Karl Herler | |
* | |
*/ | |
abstract class SearchAlbum extends SkeletonAlbum implements Observer { | |
abstract boolean searchCriteria(Photo p); | |
@Override | |
boolean extendedInvariant() { | |
// TODO Auto-generated method stub | |
return true; | |
} | |
@Override | |
public Set<Photo> getPhotos() { | |
return photos; | |
} | |
/** | |
* This adds a photo to the album if it matches the search criteria that we | |
* have defined for the album, a implementation of the template pattern | |
* basically. | |
* | |
* The searchCritera method is abstract in this class but is made concrete | |
* in the concrete implementations of this (like greatPhotos and flaggedPhotos) | |
* | |
* @param p | |
* The photo to speculate on whether it should be added or not. | |
*/ | |
public void addPhoto(Photo p) { | |
System.out.println(searchCriteria(p)); | |
if (searchCriteria(p)) { | |
photos.add(p); | |
} else { | |
photos.remove(p); //in case the operation was a update that made it unfit. | |
} | |
} | |
/** | |
* doesn't do shit. | |
*/ | |
public void removePhotos(Set<Photo> p) { | |
throw new UnsupportedOperationException(); | |
} | |
@Override | |
public void update(Observable arg0, Object arg1) { | |
addPhoto((Photo) arg0); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package model; | |
import java.util.HashSet; | |
import java.util.Set; | |
/** | |
* Didn't think of a good name, I would have used ProtoAlbum but that's a bit | |
* confusing I guess, and it's soon halloween. | |
* @author Karl Herler | |
* | |
*/ | |
public abstract class SkeletonAlbum { | |
private String name; //The name of the album | |
protected Set<Photo> photos = new HashSet<Photo>(); //The actual photos | |
/* mutability is whether a album is deletable or photos are addable to it | |
* basically all "Album" are mutable while all "searchAlbum" aren't. | |
*/ | |
protected boolean mutable = false; | |
abstract boolean extendedInvariant(); | |
public abstract Set<Photo> getPhotos(); | |
abstract void removePhotos(Set<Photo> p); | |
/** | |
* Used in tests so can't be private, this adds a extended invariant which | |
* is defined in the concrete implementations of this class so they can | |
* control any injected volatilities. | |
* | |
* @return | |
* true if the invariant holds, false other vice | |
*/ | |
public boolean invariant() { | |
return name != null && extendedInvariant(); | |
} | |
/** | |
* Returns whether or not the album is mutable, i.e. if it is changable by | |
* the user or automatic album. | |
* @return | |
* true if the album is changable, false if it is immutable. | |
*/ | |
public boolean isMutable() { | |
return mutable; | |
} | |
/** | |
* Sets the Albums name to the specified input. | |
* Used by other classes, cant be private | |
* (just added for good behavior and testing) | |
* | |
* @param s | |
* A String containing the new name of the album. | |
*/ | |
public void setName(String s) { | |
/* NOTE: I see no reason that an empty string as name would not be a | |
* valid name, if the user wants a album with the name "" or " " it is | |
* up to the user and shouldn't be enforced, it is still a name just | |
* rather...short. | |
*/ | |
assert s!=null; //precondition | |
name = s; | |
assert getName()==s && invariant(); //postcondition | |
} | |
/** | |
* Returns the name of the Album. | |
* Used by other methods, can't be private | |
* | |
* @return | |
* The album name. | |
*/ | |
public String getName() { return name; } | |
/** | |
* toString() returns the name of the album, mostly in order for JTree to | |
* show the album name instead of objId | |
* Used by other methods, can't be private | |
* @return | |
* The name of the album. | |
*/ | |
public String toString() { return name; } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment