Software Craftsmanship
OOP Crash Course
October 11, 2016
Object Oriented Programming is all about encapsulating moving parts in self-sustainable objects.
There are 4 core OOP concepts:
We are going to focus on the first two core concepts in this section.
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?
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.
Is the a good or bad example of encapsulation?
public class Point2 {
double getX();
double getY();
void setLocation(double x, double y);
}
Is the a good or bad example of encapsulation?
public class 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".
What is an association?
An association is simply a reference to another object.
class Class1 {
private Class2 class2Instance;
public Class1() {
this.class2Instance = Class2();
}
}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.
Composition or Aggregation?
class Customer
{
private Account account;
public Customer()
{
this.account = new Account();
}
}Composition
Composition or Aggregation?
class Customer
{
private Account account;
public Customer(Account account)
{
this.account = account;
}
}Aggregation
Aggregation provides references to objects you have no control over.
What are the pitfalls of aggregation?
When is aggregation appropriate?
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);
}
}Pros/Cons?
With example 2, all interactions of note are visible at a glance.
Example 2 is deterministic
Composition provides references to objects you have complete control over.
What are the pitfalls of composition?
When is composition appropriate?
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
How is Abstraction different from Encapsulation?
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);
}
}
}public interface ILogger
{
bool LogError(string message)
}What are the differences?
When would you prefer one over the other?
To summarize, abstract classes are for creating extensible systems. Interfaces are for ensuring behaviors.
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);
}
public interface A {
default void foo(){
System.out.println("Calling A.foo()");
}
}
public class Clazz implements A {
}
http://bit.ly/2e4iJFW
And remember!
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
(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.
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.
Functions have to abide by two rules
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.
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.