Skip to content

Instantly share code, notes, and snippets.

@NightlyNexus
Last active August 29, 2015 14:05
Show Gist options
  • Save NightlyNexus/1256e4e36428b44ebf57 to your computer and use it in GitHub Desktop.
Save NightlyNexus/1256e4e36428b44ebf57 to your computer and use it in GitHub Desktop.
Explanation of a failure of OO design and encapsulation

Please read, compile, and run the provided code. Try GiveADogABone with ArrayListNaive (commented out, line 30) and ArrayListBest.

Explanation of a failure of Object-Oriented design and encapsulation.

I should not have to know how a public method is implemented; that is a core principle of OOP. However, this is an issue when public methods (that I have overriden and called super in) may call other public methods (that I have overriden and called super in).

You may think this is a trivial problem in the case provided, but think if adding were not such a simple task. Let us say that I did not understand at all how add or addAll worked or if addAll did some other unknown tasks in the background, so I absolutely need to call super on both add and addAll.

The problem is that, without knowing how my ArrayList is implemented (naive vs. best), I do not know whether I should override add to insert my bark or BOTH add and addAll to insert my bark. Does addAll call add, or do both add and addAll call a private helper method to do the actual implentation? As the user of the ArrayList API, I have no idea.

My conclusion is that the standard should be to call a private helper method to do actual implementation when making public methods, so the user extending the class does not have to guess (although, he will have to rely on the implementer of the API to follow the standard). The user will know that he should override all the public methods that he wants his logic to exist in.

import java.util.Collection;
/**
* @author Eric Cochran
*/
public class ArrayListBest<T> {
private static final int DEFAULT_CAPACITY = 10;
private final int initialCapacity;
private T[] arr;
private int index;
public ArrayListBest() {
this(DEFAULT_CAPACITY);
}
public ArrayListBest(int initialCapacity) {
this.initialCapacity = initialCapacity;
init();
}
private void init() {
arr = (T[]) new Object[initialCapacity];
index = 0;
}
public void add(T data) {
addHelper(data);
}
public void addAll(Collection<T> collection) {
for (T item : collection) {
addHelper(item);
}
}
private void addHelper(T data) {
if (data == null) {
return;
}
if (index >= arr.length) {
T[] temp = (T[]) new Object[arr.length * 2];
int i = 0;
for (T item : arr) {
temp[i] = item;
i++;
}
arr = temp;
}
arr[index] = data;
index++;
}
}
import java.util.Collection;
/**
* @author Eric Cochran
*/
public class ArrayListNaive<T> {
private static final int DEFAULT_CAPACITY = 10;
private final int initialCapacity;
private T[] arr;
private int index;
public ArrayListNaive() {
this(DEFAULT_CAPACITY);
}
public ArrayListNaive(int initialCapacity) {
this.initialCapacity = initialCapacity;
init();
}
private void init() {
arr = (T[]) new Object[initialCapacity];
index = 0;
}
public void add(T data) {
if (data == null) {
return;
}
if (index >= arr.length) {
T[] temp = (T[]) new Object[arr.length * 2];
int i = 0;
for (T item : arr) {
temp[i] = item;
i++;
}
arr = temp;
}
arr[index] = data;
index++;
}
public void addAll(Collection<T> collection) {
for (T item : collection) {
this.add(item);
}
}
}
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author Eric Cochran
*/
public class GiveADogABone {
public static void main(String[] args) {
final int numBones = 5;
final List<Bone> bonesInHand = new ArrayList<Bone>(numBones);
final BarkerList<Bone> bonesGivenToDog = new BarkerList<Bone>(numBones);
// filling my hands with bones
for (int i = 0; i < numBones; i++) {
bonesInHand.add(new Bone());
}
// giving the bones to the dog
bonesGivenToDog.addAll(bonesInHand);
bonesInHand.clear();
// How many times does the dog thank me (by barking)?
}
private static class Bone {}
/**
* @author Eric Cochran
*/
public static class BarkerList<T>
extends /*ArrayListNaive*/ArrayListBest<T> {
public BarkerList() {
super();
}
public BarkerList(int initialCapacity) {
super(initialCapacity);
}
@Override
public void add(T obj) {
bark();
super.add(obj);
}
@Override
public void addAll(Collection<T> objCollection) {
for (int i = 0; i < objCollection.size(); i++) {
bark();
}
super.addAll(objCollection);
}
private static void bark() {
System.out.println("Bark!");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment