Software Craftsmanship
OOP Crash Course
September 18, 2016
Object Oriented Programming
Object Oriented Programming is all about encapsulating moving parts into self-sustainable objects.
There are 4 core OOP concepts
- Encapsulation
- Abstraction
- Inheritance
- Polymorphism
We are going to focus on the first three in this lecture.
Encapsulation
Encapsulation is a simple concept; it's the black box that contains all of the internal implementation details. There are multiple scopes that can be encapsulated but for this class we will focus on class level encapsulation.
What are the primary goals of encapsulation?
- Reusable code to reduce development times and improve maintainability
- The ability to alter your program with minimal side effects
Encapsulation Example
Is the a good or bad example of encapsulation?
public class Point1 {
public double x;
public double y;
}
Remember the primary goals of Encapsulation are.
- Reusable code to reduce development times and improve maintainability.
- The ability to alter your program with minimal side effects.
How about this?
Is the a good or bad example of encapsulation?
public class Point2 {
double getX();
double getY();
void setLocation(double x, double y);
}
Or this?
Is the a good or bad example of encapsulation?
public interface Point3 {
double getX();
double getY();
void setCartesian(double x, double y);
double getR();
double getTheta();
void setPolar(double radius, double theta);
}
You can go from example 2 to example 3 without performing "Shotgun Surgery".
Association
What is an association?
An association is simply a reference to another object.
class Class1 {
private Class2 class2Instance;
public Class1() {
this.class2Instance = Class2();
}
}Types of Associations
Aggregation
-
Aggregation is when Class A has a reference to Object B and Object B is able to exist outside Class A.
Composition
-
Composition is when Class A has a reference to Object B, but Object B is tied to the life cycle of Class A.
A Quick Quiz
Composition or Aggregation?
class Customer
{
private Account account;
public Customer()
{
this.account = new Account();
}
}Composition
A Quick Quiz
Composition or Aggregation?
class Customer
{
private Account account;
public Customer(Account account)
{
this.account = account;
}
}Aggregation
DoubleLinkedList Example
public class DoubleLinkedList
{
public synchronized void addLast(T me)
{
if ( first == null )
{
// empty list.
first = me;
}
else
{
last.next = me;
me.prev = last;
}
last = me;
size++;
}
}public class DoubleLinkedListNode
{
private final T payload;
/** Double Linked list references */
public DoubleLinkedListNode<T> prev;
/** Double Linked list references */
public DoubleLinkedListNode<T> next;
public DoubleLinkedListNode(T payloadP)
{
payload = payloadP;
}
public T getPayload()
{
return payload;
}
}Aggregation
Aggregation provides references to objects you have no control over.
Aggregation
What are the pitfalls of aggregation?
- Aggregated objects can be changed at any time or even set to null.
- Functions that leverage aggregated objects behave differently even when used with the same parameters.
Aggregation
When is aggregation appropriate?
- When the state of the aggregated object is immutable or irrelevant.
Composition
Composition provides references to objects you have complete control over.
Composition
What are the pitfalls of composition?
- Code duplication.
Composition
When is composition appropriate?
- When there is a "has-a" relation ship
Composition
Does composition introduce coupling?

Abstraction
Abstraction is a technique for arranging complexity of computer systems. It works by establishing a level of complexity on which a person interacts with the system, suppressing the more complex details below the current level. - Wikipedia
Abstraction vs Encapsulation
How is Abstraction different from Encapsulation?
- Encapsulation hides internal details
- Abstraction reduces complexity
Abstract Classes
public abstract class LoggerBase {
protected LoggerBase() {
logger = log4net.LogManager.GetLogger(this.LogPrefix);
log4net.Config.DOMConfigurator.Configure();
}
protected void LogError(string message) {
if (this.logger.IsErrorEnabled) {
this.logger.Error(message);
}
}
}Interfaces
public interface ILogger
{
bool LogError(string message)
}Abstract Classes vs Interfaces
What are the differences?
- Both let you define behaviors.
- Abstract classes allow you to implement behaviors.
When would you prefer one over the other?
- Abstract Classes can define default behaviors and can influence the the design of their sub classes.
- Interfaces allow true plug and play interchangeability.
To summarize, abstract classes are for creating extensible systems. Interfaces are for ensuring behaviors.
Commons Collection Example
public class LRUMap<K, V> extends AbstractLinkedMap<K, V>
implements BoundedMap<K, V>, Serializable, Cloneable {
/**
* A <code>Map</code> implementation with a fixed maximum size which removes
* the least recently used entry if an entry is added when full.
*/
}
public abstract class AbstractLinkedMap<K, V>
extends AbstractHashedMap<K, V> implements OrderedMap<K, V> {
}
public interface BoundedMap<K, V> extends IterableMap<K, V> {
boolean isFull();
int maxSize();
}
public interface OrderedMap<K, V> extends IterableMap<K, V> {
boolean firstKey();
int lastKey();
K nextKey(K key);
K previousKey(K key);
}
To Simplify
- Abstract classes contain shared code
- Interfaces enforce behaviors
- Base classes are the implementation of a specific use case
What about Interfaces that Allow Implementations?
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) {
//Can require a parameter to extend multiple protocols
print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
public interface A {
default void foo(){
System.out.println("Calling A.foo()");
}
}
public class Clazz implements A {
}
OOP Exercise
https://github.kdc.capitalone.com/gist/kat269/0f15e3dae3c15948aa9c5023f3974fda
- Abstract classes contain shared code
- Interfaces enforce behaviors
- Base classes are the implementation of a specific use case
And remember!
Thoughts on Aggregation
Often times people will use aggregation to reduce boiler plate and prevent continually passing around variables.
class Request {
public Dispatcher dispatcher;
public Request(Dispatcher dispatcher) {
this.dispatcher = dispatcher;
}
public send() {
this.dispatcher.send(this.headers, this.body, this.timeout);
}
}class Request {
public send(final Dispatcher dispatcher) {
dispatcher.send(this.headers, this.body, this.timeout);
}
}Thoughts on Aggregation
Pros/Cons?
-
With example 2, all interactions of note are visible at a glance.
-
Example 2 is deterministic
Functional Ideals Help Keep Things Simple
Imperative Programming
"In computer science, imperative programming is a programming paradigm that uses statements that change a program's state. In much the same way that the imperative mood in natural languages expresses commands, an imperative program consists of commands for the computer to perform." - Wikipedia
Functional Programming
"In computer science, functional programming is a programming paradigm—a style of building the structure and elements of computer programs—that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data." - Wikipedia
Functional Ideals Help Keep Things Simple
Pros/Cons?
Advantages of Functional Programming
(According to Microsoft)
-
Increased readability and maintainability. This is because each function is designed to accomplish a specific task given its arguments. The function does not rely on any external state.
-
Easier reiterative development. Because the code is easier to refactor, changes to design are often easier to implement. For example, suppose you write a complicated transformation, and then realize that some code is repeated several times in the transformation. If you refactor through a pure method, you can call your pure method at will without worrying about side effects.
-
Easier testing and debugging. Because pure functions can more easily be tested in isolation, you can write test code that calls the pure function with typical values, valid edge cases, and invalid edge cases.
(According to John Carmack)
-
A large fraction of the flaws in software development are due to programmers not fully understanding all the possible states their code may execute in. ... Programming in a functional style makes the state presented to your code explicit, which makes it much easier to reason about.
-
Reusability. It is much easier to transplant a pure function to a new environment. ... How many times have you known there was some code that does what you need in another system, but extricating it from all of its environmental assumptions was more work than just writing it over?
-
Easier testing and debugging. Because pure functions can more easily be tested in isolation, you can write test code that calls the pure function with typical values, valid edge cases, and invalid edge cases.
So What is Functional Programming?
Functions have to abide by two rules
- There are no side effects
- The same input results in the same output
Is it possible for all functions to be functional?
A program that never alters state is probably not doing anything worth doing. Databases, file systems, etc... are never going to be deterministic. This is fine, the functional ideal is to compose stateless data capable of describing the transformation and then applying it all at once.
Collections Example
Imperative Collection
list = NewList();
list.Add(1)
list.Add(3)
list.Add(5)
list.Add(7)Functional Collection
list = NewList();
list = list.add(1)
list = list.Add(3)
list.Add(5)
list = list.Add(7)Results [1,3,5,7]. The state of list changes each time add is called.
Results [1,3,7]. The list is overwritten each time the internal state never changes.
Functional Examples in OOP Languages
public class Program {
private static string aMember = "StringOne";
public static void HypenatedConcat(string appendStr) {
aMember += '-' + appendStr;
}
public static void Main() {
HypenatedConcat("StringTwo");
Console.WriteLine(aMember); //StringOne-StringTwo
HypenatedConcat("StringTwo");
Console.WriteLine(aMember); //StringOne-StringTwo-StringTwo
}
}Is HypenatedConcat "Pure"?
No: HypenatedConcat will never execute the same way twice. This example is especially bad because multiple libraries in the same process space will be altering the aMember variable.
Functional Examples in OOP Languages
public class Program {
public static void HypenatedConcat(StringBuilder sb, String appendStr) {
sb.Append('-' + appendStr);
}
public static void Main() {
StringBuilder sb1 = new StringBuilder("StringOne");
HypenatedConcat(sb1, "StringTwo");
Console.WriteLine(sb1); //StringOne-StringTwo
HypenatedConcat(sb1, "StringTwo");
Console.WriteLine(sb1); //StringOne-StringTwo-StringTwo
}
}Is HypenatedConcat "Pure"?
No: StringBuilder sb is changed in main
Many Design Principles and
Patterns are Tools to Reduce State
Imperative HTTP Request (Java Jersey Jackson Client)
HTTPBasicAuthFilter filter = new HTTPBasicAuthFilter("user", "password");
//Client is immutable. ClientBuilder returns clones of its self after each function call
Client client = ClientBuilder.newBuilder()
.register(JacksonFeature.class)
.addFilter(filter)
.build();
//WebTarget returns clones of its self after each function call
WebTarget target = client.target("http://localhost:8080").path("resource");
//The form is the only thing here that is mutable
Form form = new Form();
form.param("x", "foo");
form.param("y", "bar");
Response response = target.request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE), Response.class);
Map<String, Object> jsonResponse = response(Map.class);A Functional Example
Functional programs strive to be data driven vs object driven.
-
Was the previous example class or data driven?
(client/post "http://localhost:8080"
{:basic-auth ["user" "password"]
:form-params
{:x "foo"
:y "bar"}
:as :json})Data driven Clojure Example
A Functional Example
Many modern OOP libraries are increasingly data driven.
Map<String, String> data = new HashMap<String, String>();
data.put("x", "foo");
data.put("y", "bar");
String response = post("http://localhost:8080")
.basic("user", "password")
.form(data)
.body();
JSONObject obj = new JSONObject(response);OOP Crash Course
By cof_softwarecraftsmanship
OOP Crash Course
- 508