OMG, The hackathon is coming
https://goo.gl/xZnh1c
Idan Felix
Android
Design Patterns
+
Not this kind of patterns
The term Design Patterns also means UX patterns.
That’s not the kind of the Design Patterns we’ll discuss today.
Goals
Learn the basic why-and-what of Design Patterns
Inspire to learn and use patterns
improve your code-reading skills
improve your code-writing skills
improve your code-communication skills
Agenda
- 2 Truths about software development in the long run
- Worst Feeling
- Code Smells
- Design Patterns Party
- Abstract Server, Observer
- Static Factory Method
- Builder pattern
Warning:
There are many
BIG WORDS
in this session.
Fact of life
Over time,
New code turns to Old code,
and Old code turns to Legacy code
Read more: https://en.wikipedia.org/wiki/Software_rot
Code Rot, or Code Decay, is the slow deterioration of software.
Code Smells - Symptoms of Bad Design
- Rigidity
- Fragility
- Immobility
- Viscosity
- Needless complexity
- Needless Repetition
Source: Robert C. Martin (Uncle Bob)
- Code is hard to change
- Design is easy to break
- Design is not reusable
- Easier to do the wrong thing
- Design contains useless elements
- Same code appears again and again
Code Smells - Symptoms of Bad Design
- Rigidity
- Fragility
- Immobility
- Viscosity
- Needless complexity
- Needless Repetition
Source: Robert C. Martin (Uncle Bob)
- “Hmm.. That was a lot more complicated than I thought.“
- “X is always on the bug list / we’re afraid to touch it“
- “Yeah, It’s the same, but we have to copy-paste its code“
- “No problem, let’s hack it like … and fix it later“
- “High wtf/min ratio in a public CR“
- “Haven’t I seen this line before? || Ctrl+(C→V)“
Design Patterns
Re-usable form of a solution to a design problem.
Design patterns are great, as they:
- Name common code structures, so we can discuss them
- Time proven solutions, that make code easier to understand
- Fun at Job Interviews
- Really overloaded term
Design Patterns
There are many sources for Design Patterns, but these 4 books are a
great starting point
- Design Patterns (GoF)
- Code Complete (Microsoft)
- Effective Java (Bloch)
- PoEAA (Fowler)
Design Patterns
As with everything, there are a few challenges when choosing which
patterns to use and how:
- Some patterns are Anti-patterns in general,
Some patterns are Anti-patterns on Android.
- Knowing when to use a design pattern,
and knowing which one to choose
Design patterns are like spices.
- Creational Patterns - patterns for creating objects
- Structural Patterns - patterns for classes composition
- Behavioral Patterns - patterns for objects communication
Design Patterns - GoF Classification
What are we going to read
Android is Open Source
so we’re about to look at some patterns and their implementation in
the framework.
You can read the framework’s code here:
https://github.com/android/platform_frameworks_base/tree/master/core/java/android
Design patterns warm-up:
The Abstract Server
Design Pattern
Behavioral patterns
Abstract Server
This is the most basic design pattern,
used to describe a simple OO Principle:
Prefer composition over inheritance
Consider a switch that turns on a lamp:
Switch Lamp
Turns on
+ click() + TurnOn()
+ TurnOff()
+ isOn()
How can we use the
Switch to turn on the
boiler?
How can we Unit Test a
Switch?
Abstract Server
Extract an interface from the
lamp and separate the lamp
and the switch.
You’ll be able to use the same
switch with anything else you
like.
Switch Switchable
Turns on
+ click() + TurnOn()
+ TurnOff()
+ isOn()
Lamp
+ TurnOn()
+ TurnOff()
+ isOn()
extends
You already know this pattern
This is how callbacks are
implemented.
Let’s see the related code.
View
View.OnClick
Listener
invokes
+ performClick + onClick
MainActivity
+ onClick()
implements
View.performClick()
/**
* Call this view's OnClickListener, if it is defined. Performs all normal
* actions associated with clicking: reporting accessibility event, playing
* a sound, etc.
*
* @return True there was an assigned OnClickListener that was called, false
* otherwise is returned.
*/
public boolean performClick() {
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
return result;
}
https://github.com/android/platform_frameworks_base/blob/mast
View.OnClickListener
/**
* Interface definition for a callback to be invoked when a view is clicked.
*/
public interface OnClickListener {
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
void onClick(View v);
}
https://github.com/android/platform_frameworks_base/blob/mast
The Observer Pattern
An extension of the Abstract Server pattern, enables to use many
abstract servers.
Instead of holding a listener
in a single field, hold a collection.
This way, you can add
more than one listener.
https://en.wikipedia.org/wiki/Observer_pattern
Sample (Seen last week)
The ViewTreeObserver is a great example.
It’s an object that can notify you on things that happen on the Views
tree, such as when animation completes, scroll changes, and etc.
ViewTreeObserver - Ton of listener collections
// Recursive listeners use CopyOnWriteArrayList
private CopyOnWriteArrayList<OnWindowFocusChangeListener> mOnWindowFocusListeners;
private CopyOnWriteArrayList<OnWindowAttachListener> mOnWindowAttachListeners;
private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
private CopyOnWriteArrayList<OnEnterAnimationCompleteListener> mOnEnterAnimationCompleteListeners;
// Non-recursive listeners use CopyOnWriteArray
// Any listener invoked from ViewRootImpl.performTraversals() should not be recursive
private CopyOnWriteArray<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
private CopyOnWriteArray<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
private CopyOnWriteArray<OnScrollChangedListener> mOnScrollChangedListeners;
private CopyOnWriteArray<OnPreDrawListener> mOnPreDrawListeners;
private CopyOnWriteArray<OnWindowShownListener> mOnWindowShownListeners;
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewTreeObserver.java
ViewTreeObserver - sample registration
public void addOnWindowShownListener(OnWindowShownListener listener) {
checkIsAlive();
if (mOnWindowShownListeners == null) {
mOnWindowShownListeners = new CopyOnWriteArray<OnWindowShownListener>();
}
mOnWindowShownListeners.add(listener);
if (mWindowShown) {
listener.onWindowShown();
}
}
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewTreeObserver.java
ViewTreeObserver - sample invocation
public final void dispatchOnWindowShown() {
mWindowShown = true;
final CopyOnWriteArray<OnWindowShownListener> listeners = mOnWindowShownListeners;
if (listeners != null && listeners.size() > 0) {
CopyOnWriteArray.Access<OnWindowShownListener> access = listeners.start();
try {
int count = access.size();
for (int i = 0; i < count; i++) {
access.get(i).onWindowShown();
}
} finally {
listeners.end();
}
}
}
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewTreeObserver.java
Creational Patterns
Static Factory Method - Flavor 1
Replace a constructor with a static (named) method, and hide the
constructor as private.
This way, the only (sane) way to create such class is via the static
factory method.
Toast.makeText(...)
public class Toast {
// ...
public static Toast makeText(Context context, CharSequence text, @Duration int duration) {
Toast result = new Toast(context);
LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
tv.setText(text);
result.mNextView = v;
result.mDuration = duration;
return result;
}
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/AlertDialog.java#L438
Static Factory Method - Flavor 2
Create a static factory method for stuff your class might need.
public class SomeActivity
public Intent createSomeActivityIntent(int extraInt, String extraString){
// Create an intent, add the extras properly, and return the intent
}
}
The Builder Pattern
Sometimes, creation is more complicated, and you want to create a
DSL for the creation, over creating many different constructors.
This reduces mistakes (10x to code-autocompletion) and improves
code readability and discoverability.
The Builder Pattern
https://en.wikipedia.org/wiki/Builder_pattern
You Are Here
AlertDialog.Builder
public static class Builder {
public Builder setTitle(@StringRes int titleId)
public Builder setTitle(CharSequence title)
public Builder setCustomTitle(View customTitleView)
public Builder setMessage(@StringRes int messageId)
public Builder setIcon(@DrawableRes int iconId)
public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener)
public Builder setNegativeButton(@StringRes int textId, final OnClickListener listener)
public Builder setCancelable(boolean cancelable)
public Builder setItems(@ArrayRes int itemsId, final OnClickListener listener)
public Builder setAdapter(final ListAdapter adapter, final OnClickListener listener)
public Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, final OnClickListener listener)
public Builder setView(int layoutResId)
// ...
public AlertDialog create()
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/AlertDialog.java#L438
NotificationCompat.Builder
public static class Builder
public Builder setUsesChronometer(boolean b)
public Builder setSmallIcon(int icon)
public Builder setContentTitle(CharSequence title)
public Builder setContentText(CharSequence text)
public Builder setSubText(CharSequence text)
public Builder setNumber(int number)
public Builder setProgress(int max, int progress, boolean indeterminate)
public Builder setContent(RemoteViews views)
public Builder setDeleteIntent(PendingIntent intent)
public Builder setTicker(CharSequence tickerText)
public Builder setLargeIcon(Bitmap icon)
public Builder setSound(Uri sound)
public Builder setVibrate(long[] pattern)
public Builder setOngoing(boolean ongoing)
public Builder setAutoCancel(boolean autoCancel)
public Builder setPriority(int pri)
// ...
https://github.com/android/platform_frameworks_support/blob/master/v4/java/android/support/v4/app/NotificationCompat.java#L869
Bonus Pattern: Fluent Interface (like it’s the 90s)
Create a simple fluent interface, by having all methods return a builder, this builder.
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Hackathon Registration");
builder.setMessage("All team members must register TODAY.");
builder.setPositiveButton("OK, I'm registered", null);
builder.setNegativeButton("I'll register today", null);
AlertDialog dialog = builder.create();
vs.
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle("Hackathon Registration")
.setMessage("All team members must register TODAY.")
.setPositiveButton("OK, I'm registered", null)
.setNegativeButton("I'll register today", null)
.create();
Structural Patterns
Decorator
https://en.wikipedia.org/wiki/Decorator_pattern
an object wrapper, that adds or
changes the functionality.
Demo - Increase in Shekel Tish’im
Meal
Burger
Meal
Shnitzel
Meal
XL
Demo - Increase in Shekel Tish’im
public interface Meal {
double getPrice();
String getChips();
String getMainCourse();
String getDrink();
}
public class BurgerMeal implements Meal {
public double getPrice() { return 10; }
public String getChips() { return "Medium Chips"; }
public String getMainCourse() { return "Burger"; }
public String getDrink() { return "Medium Drink"; }
}
Demo - Increase in Shekel Tish’im
public class XL implements Meal {
private static final double XL_COST = 1.90;
private Meal meal;
public XL(Meal meal) { this.meal = meal; }
public double getPrice() {
double price = meal.getPrice() + XL_COST;
return price;
}
public String getChips() {
return "Extra large chips";
}
}
public String getMainCourse() {
return meal.getMainCourse();
}
public String getDrink() {
return "Extra large drink";
}
Exercise - Layered math problem
We have an interface for getting sets of
integers one at a time, and we have a class
that implements it and provides 1, 2, ..., n,
and code that reads such an IntProvider until it ends with n=3000.
Using decorators, write the first 5
multiples of 7 that are larger than 38,
and stop.
IntProvider
getCurrent : int
moveNext : bool
Credit: Iterator Pattern, Wikipedia
Exercise - Layered math problem
IntProvider
getCurrent : int
moveNext : bool
This is our starting point:
int n = 3000;
IntProvider heartbeat = new IntHeartBeat(n);
IntProvider result = heartbeat;
while (result.moveNext()){
System.out.println(result.getCurrent());
}
Solution - Layered math problem
IntProvider skipped = new MultiplicationsOf(heartbeat, 7);
IntProvider greaterThenThirtyEight =
new
PassGreaterThan(skipped, 38);
IntProvider takeOnlyFive =
new
TakeOnly(greaterThenThirtyEight, 5);
IntProvider result = takeOnlyFive;
Solution - Layered math problem
IntProvider skipped = new MultiplicationsOf(heartbeat, 7);
IntProvider greaterThenThirtyEight =
new
PassGreaterThan(skipped, 38);
IntProvider takeOnlyFive =
new
TakeOnly(greaterThenThirtyEight, 5);
IntProvider result = takeOnlyFive;
7, 14, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98, 105, ...
42, 49, 56, 63, 70, 77, 84, 91, 98, 105, ...
42, 49, 56, 63, 70 and STOP.
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, ...
Where is it found in the framework?
Sample of Scroll View
@Override
public void addView(View child, ViewGroup.LayoutParams params) {
if (getChildCount() > 0) {
throw new IllegalStateException("ScrollView can host only one direct child");
}
super.addView(child, params);
}
It extends FrameLayout but allows only one child.
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/ScrollView.java
Summary
What did we see
We saw a few Design Patterns
Pattern Description SRC
Abstract Server Adding abstraction to increase reusability Robert C. Martin
Observer Subscribe to things that happen GoF
Static Factory
Method
Invert ownership on creation instructions
Add compile-time safety to Intent’s Extras
Effective Java
Builder Complex building scenario, avoid 2n
constructors
GoF
Decorator Change object’s behavior without changing its
interface, its code and its usages
GoF
Any Questions?

Android design patterns

  • 1.
    OMG, The hackathonis coming https://goo.gl/xZnh1c Idan Felix Android Design Patterns +
  • 2.
    Not this kindof patterns The term Design Patterns also means UX patterns. That’s not the kind of the Design Patterns we’ll discuss today.
  • 3.
    Goals Learn the basicwhy-and-what of Design Patterns Inspire to learn and use patterns improve your code-reading skills improve your code-writing skills improve your code-communication skills
  • 4.
    Agenda - 2 Truthsabout software development in the long run - Worst Feeling - Code Smells - Design Patterns Party - Abstract Server, Observer - Static Factory Method - Builder pattern
  • 5.
    Warning: There are many BIGWORDS in this session.
  • 7.
    Fact of life Overtime, New code turns to Old code, and Old code turns to Legacy code
  • 8.
  • 9.
    Code Smells -Symptoms of Bad Design - Rigidity - Fragility - Immobility - Viscosity - Needless complexity - Needless Repetition Source: Robert C. Martin (Uncle Bob) - Code is hard to change - Design is easy to break - Design is not reusable - Easier to do the wrong thing - Design contains useless elements - Same code appears again and again
  • 10.
    Code Smells -Symptoms of Bad Design - Rigidity - Fragility - Immobility - Viscosity - Needless complexity - Needless Repetition Source: Robert C. Martin (Uncle Bob) - “Hmm.. That was a lot more complicated than I thought.“ - “X is always on the bug list / we’re afraid to touch it“ - “Yeah, It’s the same, but we have to copy-paste its code“ - “No problem, let’s hack it like … and fix it later“ - “High wtf/min ratio in a public CR“ - “Haven’t I seen this line before? || Ctrl+(C→V)“
  • 11.
    Design Patterns Re-usable formof a solution to a design problem. Design patterns are great, as they: - Name common code structures, so we can discuss them - Time proven solutions, that make code easier to understand - Fun at Job Interviews - Really overloaded term
  • 12.
    Design Patterns There aremany sources for Design Patterns, but these 4 books are a great starting point - Design Patterns (GoF) - Code Complete (Microsoft) - Effective Java (Bloch) - PoEAA (Fowler)
  • 13.
    Design Patterns As witheverything, there are a few challenges when choosing which patterns to use and how: - Some patterns are Anti-patterns in general, Some patterns are Anti-patterns on Android. - Knowing when to use a design pattern, and knowing which one to choose Design patterns are like spices.
  • 14.
    - Creational Patterns- patterns for creating objects - Structural Patterns - patterns for classes composition - Behavioral Patterns - patterns for objects communication Design Patterns - GoF Classification
  • 15.
    What are wegoing to read Android is Open Source so we’re about to look at some patterns and their implementation in the framework. You can read the framework’s code here: https://github.com/android/platform_frameworks_base/tree/master/core/java/android
  • 16.
    Design patterns warm-up: TheAbstract Server Design Pattern Behavioral patterns
  • 17.
    Abstract Server This isthe most basic design pattern, used to describe a simple OO Principle: Prefer composition over inheritance Consider a switch that turns on a lamp: Switch Lamp Turns on + click() + TurnOn() + TurnOff() + isOn() How can we use the Switch to turn on the boiler? How can we Unit Test a Switch?
  • 18.
    Abstract Server Extract aninterface from the lamp and separate the lamp and the switch. You’ll be able to use the same switch with anything else you like. Switch Switchable Turns on + click() + TurnOn() + TurnOff() + isOn() Lamp + TurnOn() + TurnOff() + isOn() extends
  • 19.
    You already knowthis pattern This is how callbacks are implemented. Let’s see the related code. View View.OnClick Listener invokes + performClick + onClick MainActivity + onClick() implements
  • 20.
    View.performClick() /** * Call thisview's OnClickListener, if it is defined. Performs all normal * actions associated with clicking: reporting accessibility event, playing * a sound, etc. * * @return True there was an assigned OnClickListener that was called, false * otherwise is returned. */ public boolean performClick() { final boolean result; final ListenerInfo li = mListenerInfo; if (li != null && li.mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); li.mOnClickListener.onClick(this); result = true; } else { result = false; } sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); return result; } https://github.com/android/platform_frameworks_base/blob/mast
  • 21.
    View.OnClickListener /** * Interface definitionfor a callback to be invoked when a view is clicked. */ public interface OnClickListener { /** * Called when a view has been clicked. * * @param v The view that was clicked. */ void onClick(View v); } https://github.com/android/platform_frameworks_base/blob/mast
  • 22.
    The Observer Pattern Anextension of the Abstract Server pattern, enables to use many abstract servers. Instead of holding a listener in a single field, hold a collection. This way, you can add more than one listener. https://en.wikipedia.org/wiki/Observer_pattern
  • 23.
    Sample (Seen lastweek) The ViewTreeObserver is a great example. It’s an object that can notify you on things that happen on the Views tree, such as when animation completes, scroll changes, and etc.
  • 24.
    ViewTreeObserver - Tonof listener collections // Recursive listeners use CopyOnWriteArrayList private CopyOnWriteArrayList<OnWindowFocusChangeListener> mOnWindowFocusListeners; private CopyOnWriteArrayList<OnWindowAttachListener> mOnWindowAttachListeners; private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners; private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners; private CopyOnWriteArrayList<OnEnterAnimationCompleteListener> mOnEnterAnimationCompleteListeners; // Non-recursive listeners use CopyOnWriteArray // Any listener invoked from ViewRootImpl.performTraversals() should not be recursive private CopyOnWriteArray<OnGlobalLayoutListener> mOnGlobalLayoutListeners; private CopyOnWriteArray<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners; private CopyOnWriteArray<OnScrollChangedListener> mOnScrollChangedListeners; private CopyOnWriteArray<OnPreDrawListener> mOnPreDrawListeners; private CopyOnWriteArray<OnWindowShownListener> mOnWindowShownListeners; https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewTreeObserver.java
  • 25.
    ViewTreeObserver - sampleregistration public void addOnWindowShownListener(OnWindowShownListener listener) { checkIsAlive(); if (mOnWindowShownListeners == null) { mOnWindowShownListeners = new CopyOnWriteArray<OnWindowShownListener>(); } mOnWindowShownListeners.add(listener); if (mWindowShown) { listener.onWindowShown(); } } https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewTreeObserver.java
  • 26.
    ViewTreeObserver - sampleinvocation public final void dispatchOnWindowShown() { mWindowShown = true; final CopyOnWriteArray<OnWindowShownListener> listeners = mOnWindowShownListeners; if (listeners != null && listeners.size() > 0) { CopyOnWriteArray.Access<OnWindowShownListener> access = listeners.start(); try { int count = access.size(); for (int i = 0; i < count; i++) { access.get(i).onWindowShown(); } } finally { listeners.end(); } } } https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewTreeObserver.java
  • 27.
  • 28.
    Static Factory Method- Flavor 1 Replace a constructor with a static (named) method, and hide the constructor as private. This way, the only (sane) way to create such class is via the static factory method.
  • 29.
    Toast.makeText(...) public class Toast{ // ... public static Toast makeText(Context context, CharSequence text, @Duration int duration) { Toast result = new Toast(context); LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null); TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message); tv.setText(text); result.mNextView = v; result.mDuration = duration; return result; } https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/AlertDialog.java#L438
  • 30.
    Static Factory Method- Flavor 2 Create a static factory method for stuff your class might need. public class SomeActivity public Intent createSomeActivityIntent(int extraInt, String extraString){ // Create an intent, add the extras properly, and return the intent } }
  • 31.
    The Builder Pattern Sometimes,creation is more complicated, and you want to create a DSL for the creation, over creating many different constructors. This reduces mistakes (10x to code-autocompletion) and improves code readability and discoverability.
  • 32.
  • 33.
    AlertDialog.Builder public static classBuilder { public Builder setTitle(@StringRes int titleId) public Builder setTitle(CharSequence title) public Builder setCustomTitle(View customTitleView) public Builder setMessage(@StringRes int messageId) public Builder setIcon(@DrawableRes int iconId) public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener) public Builder setNegativeButton(@StringRes int textId, final OnClickListener listener) public Builder setCancelable(boolean cancelable) public Builder setItems(@ArrayRes int itemsId, final OnClickListener listener) public Builder setAdapter(final ListAdapter adapter, final OnClickListener listener) public Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, final OnClickListener listener) public Builder setView(int layoutResId) // ... public AlertDialog create() https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/AlertDialog.java#L438
  • 34.
    NotificationCompat.Builder public static classBuilder public Builder setUsesChronometer(boolean b) public Builder setSmallIcon(int icon) public Builder setContentTitle(CharSequence title) public Builder setContentText(CharSequence text) public Builder setSubText(CharSequence text) public Builder setNumber(int number) public Builder setProgress(int max, int progress, boolean indeterminate) public Builder setContent(RemoteViews views) public Builder setDeleteIntent(PendingIntent intent) public Builder setTicker(CharSequence tickerText) public Builder setLargeIcon(Bitmap icon) public Builder setSound(Uri sound) public Builder setVibrate(long[] pattern) public Builder setOngoing(boolean ongoing) public Builder setAutoCancel(boolean autoCancel) public Builder setPriority(int pri) // ... https://github.com/android/platform_frameworks_support/blob/master/v4/java/android/support/v4/app/NotificationCompat.java#L869
  • 35.
    Bonus Pattern: FluentInterface (like it’s the 90s) Create a simple fluent interface, by having all methods return a builder, this builder. AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Hackathon Registration"); builder.setMessage("All team members must register TODAY."); builder.setPositiveButton("OK, I'm registered", null); builder.setNegativeButton("I'll register today", null); AlertDialog dialog = builder.create(); vs. AlertDialog dialog = new AlertDialog.Builder(this) .setTitle("Hackathon Registration") .setMessage("All team members must register TODAY.") .setPositiveButton("OK, I'm registered", null) .setNegativeButton("I'll register today", null) .create();
  • 36.
  • 37.
  • 38.
    Demo - Increasein Shekel Tish’im Meal Burger Meal Shnitzel Meal XL
  • 39.
    Demo - Increasein Shekel Tish’im public interface Meal { double getPrice(); String getChips(); String getMainCourse(); String getDrink(); } public class BurgerMeal implements Meal { public double getPrice() { return 10; } public String getChips() { return "Medium Chips"; } public String getMainCourse() { return "Burger"; } public String getDrink() { return "Medium Drink"; } }
  • 40.
    Demo - Increasein Shekel Tish’im public class XL implements Meal { private static final double XL_COST = 1.90; private Meal meal; public XL(Meal meal) { this.meal = meal; } public double getPrice() { double price = meal.getPrice() + XL_COST; return price; } public String getChips() { return "Extra large chips"; } } public String getMainCourse() { return meal.getMainCourse(); } public String getDrink() { return "Extra large drink"; }
  • 41.
    Exercise - Layeredmath problem We have an interface for getting sets of integers one at a time, and we have a class that implements it and provides 1, 2, ..., n, and code that reads such an IntProvider until it ends with n=3000. Using decorators, write the first 5 multiples of 7 that are larger than 38, and stop. IntProvider getCurrent : int moveNext : bool Credit: Iterator Pattern, Wikipedia
  • 42.
    Exercise - Layeredmath problem IntProvider getCurrent : int moveNext : bool This is our starting point: int n = 3000; IntProvider heartbeat = new IntHeartBeat(n); IntProvider result = heartbeat; while (result.moveNext()){ System.out.println(result.getCurrent()); }
  • 43.
    Solution - Layeredmath problem IntProvider skipped = new MultiplicationsOf(heartbeat, 7); IntProvider greaterThenThirtyEight = new PassGreaterThan(skipped, 38); IntProvider takeOnlyFive = new TakeOnly(greaterThenThirtyEight, 5); IntProvider result = takeOnlyFive;
  • 44.
    Solution - Layeredmath problem IntProvider skipped = new MultiplicationsOf(heartbeat, 7); IntProvider greaterThenThirtyEight = new PassGreaterThan(skipped, 38); IntProvider takeOnlyFive = new TakeOnly(greaterThenThirtyEight, 5); IntProvider result = takeOnlyFive; 7, 14, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98, 105, ... 42, 49, 56, 63, 70, 77, 84, 91, 98, 105, ... 42, 49, 56, 63, 70 and STOP. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, ...
  • 45.
    Where is itfound in the framework? Sample of Scroll View @Override public void addView(View child, ViewGroup.LayoutParams params) { if (getChildCount() > 0) { throw new IllegalStateException("ScrollView can host only one direct child"); } super.addView(child, params); } It extends FrameLayout but allows only one child. https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/ScrollView.java
  • 46.
  • 47.
    What did wesee We saw a few Design Patterns Pattern Description SRC Abstract Server Adding abstraction to increase reusability Robert C. Martin Observer Subscribe to things that happen GoF Static Factory Method Invert ownership on creation instructions Add compile-time safety to Intent’s Extras Effective Java Builder Complex building scenario, avoid 2n constructors GoF Decorator Change object’s behavior without changing its interface, its code and its usages GoF
  • 48.