單例模式
概念:
確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。
優(yōu)點(diǎn):
- 對(duì)于那些比較耗內(nèi)存的類,只實(shí)例化一次可以大大提高性能,尤其是在移動(dòng)開發(fā)中。
- 保持程序運(yùn)行的時(shí)候,始終只有一個(gè)實(shí)例存在內(nèi)存中
例子:
public class Singleton {
private static volatile Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
編寫單例模式,需要記住的特點(diǎn):
- 必須防止外部可以調(diào)用構(gòu)造函數(shù)進(jìn)行實(shí)例化,因此構(gòu)造函數(shù)必須私有化。
- 必須定義一個(gè)靜態(tài)函數(shù)獲得該單例getInstance();
- 單例使用volatile修飾,volatile可以保證不同線程對(duì)這個(gè)變量進(jìn)行操作時(shí)的可見性,即一個(gè)線程修改了某個(gè)變量的值,這新值對(duì)其他線程來說是立即可見的。
- 使用synchronized 進(jìn)行同步處理,并且雙重判斷是否為null,我們看到synchronized (Singleton.class)里面又進(jìn)行了是否為null的判斷,這是因?yàn)橐粋€(gè)線程進(jìn)入了該代碼,如果另一個(gè)線程在等待,這時(shí)候前一個(gè)線程創(chuàng)建了一個(gè)實(shí)例出來完畢后,另一個(gè)線程獲得鎖進(jìn)入該同步代碼,實(shí)例已經(jīng)存在,沒必要再次創(chuàng)建,因此這個(gè)判斷是否是null還是必須的。
Build模式
概念:
將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
優(yōu)點(diǎn):
提高代碼的可讀性。
例子:
public class Person {
private String name;
private int age;
private double height;
private double weight;
privatePerson(Builder builder) {
this.name=builder.name;
this.age=builder.age;
this.height=builder.height;
this.weight=builder.weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
static class Builder{
private String name;
private int age;
private double height;
private double weight;
public Builder name(String name){
this.name=name;
return this;
}
public Builder age(int age){
this.age=age;
return this;
}
public Builder height(double height){
this.height=height;
return this;
}
public Builder weight(double weight){
this.weight=weight;
return this;
}
public Person build(){
return new Person(this);
}
}
}
編寫一個(gè)Person類,里面有一個(gè)叫Builder的靜態(tài)內(nèi)部類,他們的屬性是一樣的。把Person類的構(gòu)造函數(shù)私有化,參數(shù)是Builder,把Builder類中的屬性對(duì)應(yīng)賦值給Person類。Builder類里面有對(duì)應(yīng)各個(gè)屬性名的方法,有點(diǎn)像Setter方法,唯一不同是返回值返回的是this。Builder類里面還有build方法,返回Person對(duì)象,return new Person(this);
然后我們就可以這樣創(chuàng)建Person類對(duì)象了:
Person.Builder builder=new Person.Builder();
Person person=builder
.name("張三")
.age(18)
.height(178.5)
.weight(67.4)
.build();
Android 里面的AlertDialog,StringBuilder,StringBuffer 都有運(yùn)用到Build模式。
觀察者模式
概念:
定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)送改變時(shí),所有依賴于它的對(duì)象都能得到通知并被自動(dòng)更新
例子:
天氣對(duì)象:
public class Weather {
private String description;
public Weather(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Weather{" +
"description='" + description + '\'' +
'}';
}
}
被觀察者:
public class Observable<T> {
List<Observer<T>> mObservers = new ArrayList<Observer<T>>();
public void register(Observer<T> observer) {
if (observer == null) {
throw new NullPointerException("observer == null");
}
synchronized (this) {
if (!mObservers.contains(observer))
mObservers.add(observer);
}
}
public synchronized void unregister(Observer<T> observer) {
mObservers.remove(observer);
}
public void notifyObservers(T data) {
for (Observer<T> observer : mObservers) {
observer.onUpdate(this, data);
}
}
}
觀察者需要實(shí)現(xiàn)的接口:
public interface Observer<T> {
void onUpdate(Observable<T> observable,T data);
}
Main函數(shù):
public class Main {
public static void main(String [] args){
Observable<Weather> observable=new Observable<Weather>();
Observer<Weather> observer1=new Observer<Weather>() {
@Override
public void onUpdate(Observable<Weather> observable, Weather data) {
System.out.println("觀察者1:"+data.toString());
}
};
Observer<Weather> observer2=new Observer<Weather>() {
@Override
public void onUpdate(Observable<Weather> observable, Weather data) {
System.out.println("觀察者2:"+data.toString());
}
};
observable.register(observer1);
observable.register(observer2);
Weather weather=new Weather("晴轉(zhuǎn)多云");
observable.notifyObservers(weather);
Weather weather1=new Weather("多云轉(zhuǎn)陰");
observable.notifyObservers(weather1);
observable.unregister(observer1);
Weather weather2=new Weather("臺(tái)風(fēng)");
observable.notifyObservers(weather2);
}
}
Android的廣播機(jī)制就是使用的觀察者模式。
原型模式
概念:
用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并通過拷貝這些原型創(chuàng)建新的對(duì)象。
要實(shí)現(xiàn)原型模式,只需要按照下面的幾個(gè)步驟去實(shí)現(xiàn)即可。
- 實(shí)現(xiàn)Clone接口:
public class Person implements Cloneable{
}
- 重寫Object的clone方法
@Override
public Object clone(){
return null;
}
- 實(shí)現(xiàn)clone方法中的拷貝邏輯
@Override
public Object clone(){
Person person=null;
try {
person=(Person)super.clone();
person.name=this.name;
person.weight=this.weight;
person.height=this.height;
person.age=this.age;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return person;
}
- 測(cè)試:
public class Main {
public static void main(String [] args){
Person p=new Person();
p.setAge(18);
p.setName("張三");
p.setHeight(178);
p.setWeight(65);
System.out.println(p);
Person p1= (Person) p.clone();
System.out.println(p1);
p1.setName("李四");
System.out.println(p);
System.out.println(p1);
}
}
- 一個(gè)對(duì)象需要提供給其他對(duì)象訪問,而且各個(gè)調(diào)用者可能都需要修改其值時(shí),可以考慮使用原型模式拷貝多個(gè)對(duì)象供調(diào)用者使用,即保護(hù)性拷貝。
注意:這里的克隆是淺克隆,只是克隆引用,所以,如果要克隆ArrayList,需要再克隆一次。
person.hobbies=(ArrayList<String>)this.hobbies.clone();
策略模式
概念:
策略模式定義了一些列的算法,并將每一個(gè)算法封裝起來,而且使它們還可以相互替換。策略模式讓算法獨(dú)立于使用它的客戶而獨(dú)立變換。
- 首先,需要定義一個(gè)策略接口。
public interface Strategy {
void travel();
}
- 然后根據(jù)不同的出行方式實(shí)行對(duì)應(yīng)的接口
public class WalkStrategy implements Strategy{
@Override
public void travel() {
System.out.println("walk");
}
public class PlaneStrategy implements Strategy{
@Override
public void travel() {
System.out.println("plane");
}
}
public class SubwayStrategy implements Strategy{
@Override
public void travel() {
System.out.println("subway");
}
}
- 此外還需要一個(gè)包裝策略的類,并調(diào)用策略接口中的方法
public class TravelContext {
Strategy strategy;
public Strategy getStrategy() {
return strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void travel() {
if (strategy != null) {
strategy.travel();
}
}
}
可以看到,應(yīng)用了策略模式后,如果我們想增加新的出行方式,完全不必要修改現(xiàn)有的類,我們只需要實(shí)現(xiàn)策略接口即可,這就是面向?qū)ο笾械膶?duì)擴(kuò)展開放準(zhǔn)則。假設(shè)現(xiàn)在我們?cè)黾恿艘环N自行車出行的方式。只需新增一個(gè)類即可。