Skip to content

Instantly share code, notes, and snippets.

@KarlHerler
Created September 26, 2012 16:47
Show Gist options
  • Save KarlHerler/3789121 to your computer and use it in GitHub Desktop.
Save KarlHerler/3789121 to your computer and use it in GitHub Desktop.
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;
}
}
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);
}
}
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