15年寫的回顧一下。
1.單例模式
DCL(Double CheckLock)
public class Singleton {
private static Singleton sInstance = null;
private Singleton(){}
public static Singleton getInstance(){
if(mInstance == null){
synchronized(Singleton.class){
if(mInstance == null){
sInstance = new Singleton();
}
}
}
return sInstance;
}
}
靜態(tài)內(nèi)部類
public class Singleton{
private Singleton(){}
private static class SingletonHolder{
public static final Singleton sInstance = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
}
優(yōu)點
- 在內(nèi)存中只有一個實例,減少內(nèi)存開支,減少系統(tǒng)性能開銷;
- 避免對資源的多重占用;
- 可以在系統(tǒng)設(shè)置全局的訪問點,優(yōu)化和共享資源訪問。
缺點
- 擴展困難;
- 如果持有Context,很容易引發(fā)內(nèi)存泄漏,此時最好傳遞個單例對象的 Context 最好是 Application Context。
2.Builder 模式
參照 Android 源碼 AlertDialog.java 經(jīng)典 Builder 模式。
http://afra55.github.io/2016/12/22/normal-dialog/
優(yōu)點
- 封裝良好。
- 建造者獨立,益于擴展。
缺點
會產(chǎn)生多余的Builder以及Director對象,消耗內(nèi)存。
3.原型模式
即克隆原始的文件獲得副本,對副本進行修改并不會影響原始文件。
需要注意的是:使用 Cloneable 實現(xiàn)拷貝時,并不會執(zhí)行構(gòu)造函數(shù)。
public class WordDocument implements Cloneable {
private String mText;
private ArrayList<String> mImages = new ArrayList<>();
public ArrayList<String> getmImages() {
return mImages;
}
public WordDocument(){
Log.d("WordDocument", "WordDocument 構(gòu)造函數(shù)");
}
@Override
protected Object clone() throws CloneNotSupportedException {
try {
WordDocument document = (WordDocument) super.clone();
document.mText = this.mText;
/* 類似于這樣的指向地址的引用,也要采用拷貝形式 */
document.mImages = (ArrayList<String>) this.mImages.clone();
return document;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void addImages(String mImages) {
this.mImages.add(mImages);
}
public String getmText() {
return mText;
}
public void setmText(String mText) {
this.mText = mText;
}
}
使用方法:
public void use(){
WordDocument originDoc = new WordDocument();
originDoc.setmText("doc");
originDoc.addImages("1");
originDoc.addImages("2");
originDoc.addImages("3");
/* 進行克隆,并進行修改,原始對象并不會被改變 */
try {
WordDocument copyDoc = (WordDocument) originDoc.clone();
copyDoc.setmText("doc copy");
copyDoc.addImages("1");
copyDoc.addImages("2");
copyDoc.addImages("3");
copyDoc.addImages("4");
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
優(yōu)點
原型模式是在內(nèi)存中二進制流的拷貝,比直接 new 一個對象性能好很多,特別是在循環(huán)體內(nèi)產(chǎn)生大量對象時。
缺點
直接在內(nèi)存中拷貝,構(gòu)造函數(shù)是不執(zhí)行的,在實際開發(fā)當中要注意這個問題。
4.工廠模式
定義一個創(chuàng)建對象的接口,讓子類決定實例化哪個類。
創(chuàng)建抽象類
/**
* Created by yangshuai in the 16:05 of 2016.01.11 .
* 抽象類
*/
public abstract class BaseFacory {
public abstract void start();
}
創(chuàng)建子類
/**
* Created by yangshuai in the 16:09 of 2016.01.11 .
* 具體工廠類
*/
public class MyFacory extends BaseFacory {
@Override
public void start() {
Log.d("MyFactory", "start");
}
}
public class MyFacory2 extends BaseFacory {
@Override
public void start() {
Log.d("MyFactory2", "start");
}
}
獲取工廠實例反射方法(僅參考)
/**
* 獲取工廠實例
* @param tClass
* @param <T>
* @return
*/
public static <T extends BaseFacory> T getInstatnce(Class<T> tClass) {
BaseFacory baseFacory = null;
try {
baseFacory = (BaseFacory) Class.forName(tClass.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (T) baseFacory;
}
使用方法
BaseFacory factoryMode = FactoryMode.getInstatnce(MyFacory.class);
if (factoryMode != null) {
factoryMode.start();
}
5.策略模式
定義了一些列算法,并分別封裝,并且互相可以替換。經(jīng)?;赜脕矶鄠€if-else或switch-case。
定義通用接口
/**
* Created by yangshuai in the 10:56 of 2016.01.29 .
*/
public interface Strategy {
public int strategy();
}
封裝算法
/**
* Created by yangshuai in the 11:37 of 2016.01.29 .
*/
public class StrategyOne implements Strategy {
@Override
public int strategy() {
Log.d("StrategyOne", "OneStrategy");
/* 算法操作 */
return 1;
}
}
/**
* Created by yangshuai in the 11:37 of 2016.01.29 .
*/
public class StrategyTwo implements Strategy {
@Override
public int strategy() {
Log.d("StrategyTwo", "TwoStrategy");
/* 算法操作 */
return 2;
}
}
使用
/**
* Created by yangshuai in the 11:39 of 2016.01.29 .
*/
public class UseStrategy {
private Strategy strategy = new StrategyOne();
public Strategy getStrategy() {
return strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public int strategy() {
return strategy.strategy();
}
}
優(yōu)點
- 結(jié)構(gòu)簡單明了,使用簡單直觀;
- 耦合度相對較低,擴展方便;
- 操作封裝更徹底,數(shù)據(jù)更安全。
缺點
隨著策略的增加,子類會變得繁多。
6.狀態(tài)模式
如果有大量的 分支 語句(if-else, switch-case)或者 要根據(jù)狀態(tài)的改變而改變行為時,狀態(tài)模式是最佳選擇。舉例如下:
創(chuàng)建狀態(tài)接口
/*
狀態(tài)接口,有三種模式,睡眠、行走、進食。
*/
public interface State{
public void sleep();
public void walk();
public void eatting();
}
創(chuàng)建行為接口
/*
動作接口,分別是唱歌、移動、玩游戲。
*/
public interface Action{
public void sing();
public void move();
public void playGame();
}
模擬各種狀態(tài)下的行為執(zhí)行方式
// 睡眠模式下的所有行為的模擬
public class SleepState implements Action{
@Override
public void sing(){
System.out.println("You are sleeping, no sing");
}
@Override
public void move(){
System.out.println("You are sleeping, no move");
}
@Override
public void playGame(){
System.out.println("You are sleeping, no playGame");
}
}
// 行走模式下的所有行為的模擬
public class WalkState implements Action{
@Override
public void sing(){
System.out.println("You can sing");
}
@Override
public void move(){
System.out.println("You can move");
}
@Override
public void playGame(){
System.out.println("You can playGame");
}
}
// 進食模式下的所有行為的模擬
public class EatingState implements Action{
@Override
public void sing(){
System.out.println("You are eatting, no sing");
}
@Override
public void move(){
System.out.println("You are eatting and you could move");
}
@Override
public void playGame(){
System.out.println("You are eatting and you could playGame");
}
}
創(chuàng)建狀態(tài)控制器
/*
控制器, 用于切換狀態(tài)和執(zhí)行行為
*/
public class StateContorller implements State {
private Action mState;
public void setState(Action s){
mState = s;
}
@Override
public void sleep(){
setState(new SleepState());
}
@Override
public void walk(){
setState(new WalkState());
}
@Override
public void eatting(){
setState(new EatingState());
}
public void sing(){
mState.sing();
}
public void move(){
mState.move();
}
public void playGame(){
mState.playGame();
}
}
使用
在不同的狀態(tài)下,執(zhí)行的行為不同:
StateContorller contorller = new StateContorller();
contorller.eatting();
contorller.move();
contorller.sleep();
contorller.sing();
contorller.walk();
contorller.playGame();
優(yōu)點
優(yōu)化了繁瑣的狀態(tài)判斷,提高了可擴展性和可維護性。像上面這個例子,使用if-else對比下就顯而易見了。
缺點
增加了類和對象的個數(shù)。
7.責(zé)任鏈模式
當多個對象都可以處理一個請求,而且由請求的某個標志決定哪個對象進行處理時使用。
請求也可以是從服務(wù)端獲取的數(shù)據(jù),根據(jù)某個特性來決定處理的對象.
請求基類
/**
* Created by yangshuai in the 21:48 of 2016.06.15 .
*/
public abstract class BaseDutyRequest {
// 請求的對象是未知,千變?nèi)f化的
private Object mObject;
public BaseDutyRequest(Object object) {
mObject = object;
}
public Object getRequestObject() {
return mObject;
}
// 這里由 一個 int 型的值來標志特性
public abstract int getDutyLevel();
}
執(zhí)行職責(zé)的基類
/**
* Created by yangshuai in the 21:43 of 2016.06.15 .
*/
public abstract class BaseDuty {
// 存儲下一個節(jié)點,最后一個節(jié)點的下個節(jié)點是null
private BaseDuty nextOne = null;
public final void setNextOne(BaseDuty baseDuty) {
nextOne = baseDuty;
}
public final BaseDuty getNextOne() {
return nextOne;
}
// 獲取請求,根據(jù)請求的特性判斷由誰來處理
public final void setDutyRequest(BaseDutyRequest request) {
if (request.getDutyLevel() == getDutyLevel()) {
doDuty(request);
} else if (getNextOne() != null) {
getNextOne().setDutyRequest(request);
} else {
beyondTheResponsibilityLevel(request);
}
}
// 執(zhí)行職責(zé)能夠處理的特性,與請求的特性進行對比
protected abstract int getDutyLevel();
// 處理請求
protected abstract void doDuty(BaseDutyRequest request);
// 在最后一個節(jié)點使用,千萬不要掉到死循環(huán)的bug中
protected void beyondTheResponsibilityLevel(BaseDutyRequest request) {
// you can do someting or not;
}
}
請求舉例
/**
* Created by yangshuai in the 22:02 of 2016.06.15 .
*/
public class DutyRequestOne extends BaseDutyRequest {
public DutyRequestOne(Object object) {
super(object);
}
@Override
public int getDutyLevel() {
return 0;
}
}
/**
* Created by yangshuai in the 22:02 of 2016.06.15 .
*/
public class DutyRequestTwo extends BaseDutyRequest {
public DutyRequestTwo(Object object) {
super(object);
}
@Override
public int getDutyLevel() {
return 0;
}
}
執(zhí)行職責(zé)舉例
/**
* Created by yangshuai in the 22:00 of 2016.06.15 .
*/
public class DutyOne extends BaseDuty {
@Override
protected int getDutyLevel() {
return 0;
}
@Override
protected void doDuty(BaseDutyRequest request) {
// do what you wan't to do;
request.getRequestObject();
}
}
/**
* Created by yangshuai in the 22:01 of 2016.06.15 .
*/
public class DutyTwo extends BaseDuty {
@Override
protected int getDutyLevel() {
return 1;
}
@Override
protected void doDuty(BaseDutyRequest request) {
// do what you wan't to do;
request.getRequestObject();
}
}
使用方法
/**
* Created by yangshuai in the 22:03 of 2016.06.15 .
*/
public class DutyMode {
public static void main(String[] args) {
// 執(zhí)行對象
DutyOne dutyOne = new DutyOne();
DutyTwo dutyTwo = new DutyTwo();
dutyOne.setNextOne(dutyTwo);
// 請求對象,請求可能是從服務(wù)器獲取的數(shù)據(jù)
DutyRequestOne dutyRequestOne = new DutyRequestOne("one");
DutyRequestTwo dutyRequestTwo = new DutyRequestTwo("two");
// 每次都從第一個節(jié)點進入
dutyOne.setDutyRequest(dutyRequestOne);
dutyOne.setDutyRequest(dutyRequestTwo);
}
}
優(yōu)點
請求和處理解耦,代碼更靈活。
缺點
當處理太多,遍歷的方式會降低性能。
8.命令模式
把執(zhí)行命令分離,記錄執(zhí)行順序。
創(chuàng)建具體執(zhí)行類(命令接收者)
/**
* Created by yangshuai in the 20:52 of 2016.06.20 .
* 在電腦上操作,有多種命令,比如 復(fù)制文件,移動文件,新建文件等。
* Compter類用于實現(xiàn)具體方法。接收各種命令來執(zhí)行方法,即接收者。
*/
public class Computer {
public void doCopy(String from, String to) {
}
public void doMove(String from, String to) {
}
public void doNewDefaultFile() {
}
}
創(chuàng)建命令接口
/**
* Created by yangshuai in the 20:48 of 2016.06.20 .
* Command 接口,定義通用執(zhí)行方法,不止一個,可能有多個執(zhí)行.
*/
public interface Command {
public void execute();
public void execute(String from, String to);
}
創(chuàng)建命令實現(xiàn)類
/**
* Created by yangshuai in the 20:58 of 2016.06.20 .
* Copy 的命令實現(xiàn)類。
*/
public class DoCopyCommand implements Command {
private final Computer mComputer;
public DoCopyCommand(Computer computer) {
mComputer = computer;
}
@Override
public void execute() {
throw new IllegalArgumentException("DoCopyCommand need from and to");
}
@Override
public void execute(String from, String to) {
mComputer.doCopy(from, to);
}
}
/**
* Created by yangshuai in the 20:58 of 2016.06.20 .
* Move 的命令實現(xiàn)類。
*/
public class DoMoveCommand implements Command {
private final Computer mComputer;
public DoMoveCommand(Computer computer) {
mComputer = computer;
}
@Override
public void execute() {
throw new IllegalArgumentException("DoMoveCommand need from and to");
}
@Override
public void execute(String from, String to) {
mComputer.doMove(from, to);
}
}
/**
* Created by yangshuai in the 20:58 of 2016.06.20 .
* New file 的命令實現(xiàn)類。
*/
public class DoNewDefaultCommand implements Command {
private final Computer mComputer;
public DoNewDefaultCommand(Computer computer) {
mComputer = computer;
}
@Override
public void execute() {
mComputer.doNewDefaultFile();
}
@Override
public void execute(String from, String to) {
throw new IllegalArgumentException("DoNewDefaultCommand do not need arguments");
}
}
創(chuàng)建請求類
/**
* Created by yangshuai in the 21:06 of 2016.06.20 .
* 這些命令都能用鼠標來在電腦上操作實現(xiàn)。
* Mouse 用于發(fā)起命令,充當請求者模式。并可以記錄執(zhí)行命令,方便取消等操作。
*/
public class Mouse {
private Command doCopyCommand;
private Command doMoveCommand;
private Command doNewDefaultCommand;
private List<Command> doCommands = new ArrayList<>();
public List<Command> getDoCommands() {
return doCommands;
}
public void setDoCopyCommand(Command doCopyCommand) {
this.doCopyCommand = doCopyCommand;
}
public void setDoMoveCommand(Command doMoveCommand) {
this.doMoveCommand = doMoveCommand;
}
public void setDoNewDefaultCommand(Command doNewDefaultCommand) {
this.doNewDefaultCommand = doNewDefaultCommand;
}
public void doCopy(String from, String to) {
if (doCopyCommand == null) {
return;
}
doCopyCommand.execute(from, to);
doCommands.add(doCopyCommand);
}
public void doMove(String from, String to) {
if (doMoveCommand == null) {
return;
}
doMoveCommand.execute(from, to);
doCommands.add(doMoveCommand);
}
public void doNewDefaultFile() {
if (doNewDefaultCommand == null) {
return;
}
doNewDefaultCommand.execute();
doCommands.add(doNewDefaultCommand);
}
}
執(zhí)行
/**
* Created by yangshuai in the 21:19 of 2016.06.20 .
* 由人來決定怎么去執(zhí)行
*/
public class People {
public static void main(String []args) {
// 要創(chuàng)建一個電腦,即命令接收者來實現(xiàn)命令
Computer computer = new Computer();
// 創(chuàng)建命令
Command doCopyCommand = new DoCopyCommand(computer);
Command doMoveCommand = new DoMoveCommand(computer);
Command doNewDefaultCommand = new DoNewDefaultCommand(computer);
// 創(chuàng)建鼠標,用來發(fā)起命令請求
Mouse mouse = new Mouse();
// 準備命令
mouse.setDoCopyCommand(doCopyCommand);
mouse.setDoMoveCommand(doMoveCommand);
mouse.setDoNewDefaultCommand(doNewDefaultCommand);
// 執(zhí)行命令
mouse.doNewDefaultFile();
mouse.doMove("from", "to");
mouse.doCopy("from", "to");
}
}
優(yōu)點
增加了擴展性,分離了請求者和接收者,弱化耦合。我覺得做大的優(yōu)點是可以記錄命令的執(zhí)行順序,進而實現(xiàn)撤銷操作。
缺點
這種寫法極大的增加了代碼量,創(chuàng)建了大量的類。如果,不需要記錄執(zhí)行命令,我覺得還是別用的好。
9. 觀察者模式
多個對象來監(jiān)聽一個行為,這個時候用觀察者模式比較好。
下面舉例,多個吃貨接收到食堂發(fā)來的食品菜單。
創(chuàng)建觀察者
import com.afra55.baseclient.util.Log;
import java.util.Observable;
import java.util.Observer;
/**
* Created by yangshuai in the 20:37 of 2016.06.21 .
* 吃貨的手機會接收到食堂發(fā)來的最新菜單,在 update 方法中接收信息
*/
public class Eater implements Observer {
private String phone;
public Eater(String phone) {
this.phone = phone;
}
@Override
public void update(Observable observable, Object data) {
Log.d("Eater", "Today's food menu: " + data +" has sent to " + phone);
}
}
創(chuàng)建被觀察者
import java.util.Observable;
/**
* Created by yangshuai in the 20:47 of 2016.06.21 .
* 食堂管理員收到新的菜單信息,發(fā)送給所有已經(jīng)注冊過的吃貨
*/
public class CanteenManager extends Observable {
public void sendNewFoodMenu(String menu) {
setChanged();
notifyObservers(menu);
}
}
關(guān)聯(lián)觀察者與被觀察者
/**
* Created by yangshuai in the 20:49 of 2016.06.21 .
*/
public class FoodMaker {
public static void main(String[] args) {
// 創(chuàng)建食堂管理員
CanteenManager canteenManager = new CanteenManager();
// 創(chuàng)建吃貨
Eater eater = new Eater("111111");
Eater eater2 = new Eater("222222");
Eater eater3 = new Eater("333333");
// 注冊吃貨
canteenManager.addObserver(eater);
canteenManager.addObserver(eater2);
canteenManager.addObserver(eater3);
// 更新食物菜單,每個注冊了的吃貨都會 在 update 方法里接收到新的信息
canteenManager.sendNewFoodMenu("米飯");
canteenManager.sendNewFoodMenu("餃子");
canteenManager.sendNewFoodMenu("嘛事");
}
}
優(yōu)點
被觀察者有信息變動觀察者都會收到信息,便于功能變更,業(yè)務(wù)擴展,同時增強了靈活性。
缺點
觀察者太多會造成性能降低,不便于問題排查。
10.備忘錄模式
備忘錄模式很簡單,在某個時刻保存某個對象的狀態(tài)或者數(shù)據(jù),或者對象的狀態(tài)不想被外界直接獲取到而是利用中間代理存儲狀態(tài)并暴露給外界,這個時候備忘錄模式是很好的選擇。
下面以看書為例,介紹備忘錄模式:
需要存儲對象的類
/**
* Created by yangshuai in the 22:40 of 2016.06.22 .
* 書本每次閱讀頁數(shù)都會加1,在不閱讀的情況下要記錄當前閱讀的頁數(shù),以便下次接著閱讀
*/
public class Book {
private int page;
/**
* 每次閱讀頁數(shù)都會加1
*/
public void read() {
page++;
}
/**
* 不閱讀,合起書本的時候頁數(shù)會變?yōu)?
*/
public void leave() {
page = 0;
}
/**
* 創(chuàng)建書簽,存儲當前閱讀的頁數(shù)
* @return
*/
public Bookmark createBookmark() {
Bookmark bookmark = new Bookmark();
bookmark.setPage(page);
return bookmark;
}
/**
* 繼續(xù)閱讀,翻到書簽的那一頁
* @param bookmark
*/
public void backToRead(Bookmark bookmark) {
page = bookmark.getPage();
}
}
創(chuàng)建備忘錄類
/**
* Created by yangshuai in the 22:43 of 2016.06.22 .
* 書簽,備忘錄該存儲的數(shù)據(jù)類
*/
public class Bookmark {
private int page = 0;
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
}
創(chuàng)建備忘錄管理員
/**
* Created by yangshuai in the 22:51 of 2016.06.22 .
* 管理書簽,用來存儲和獲取備忘錄,如果外界想獲取狀態(tài),只能通過中間管理員獲取
*/
public class People {
private Bookmark bookmark;
public Bookmark getBookmark() {
return bookmark;
}
public void setBookmark(Bookmark bookmark) {
this.bookmark = bookmark;
}
}
使用
/**
* Created by yangshuai in the 22:54 of 2016.06.22 .
*/
public class World {
public static void main(String[] args) {
// 創(chuàng)建一本書
Book book = new Book();
book.read();
// 創(chuàng)建一個管理者,管理備忘錄
People people = new People();
// 管理者存儲書簽
people.setBookmark(book.createBookmark());
// 不再閱讀書,合起書
book.leave();
// 一段時間后繼續(xù)閱讀未讀完的書,接著上次的頁數(shù)
book.backToRead(people.getBookmark());
book.read();
}
}
優(yōu)點
- 為程序提供了對象的狀態(tài)恢復(fù)機制;
- 對數(shù)據(jù)進行了封裝,使用者不必關(guān)心如何實現(xiàn)保存細節(jié),只用存儲或者獲取數(shù)據(jù)。
缺點
設(shè)計模式的通病,類的泛濫,而且存取狀態(tài)會占用資源。
11.迭代器模式
遍歷對象的時候使用,在遍歷多種容器的對象的時候使用最佳。
下面以遍歷男子高校和女子高校的信息舉例:
創(chuàng)建對象
/**
* Created by yangshuai in the 21:15 of 2016.06.30 .
* 元素對象,這里以人的信息舉例
*/
public class People {
private String name;
private int age;
public People(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + ": " + age;
}
}
創(chuàng)建迭代器接口
/**
* Created by yangshuai in the 21:12 of 2016.06.30 .
* 迭代器接口
*/
public interface Iterator {
/**
* 判斷是否還有下一個元素
* @return
*/
boolean hasNext();
/**
* 返回當前位置的元素,并將位置參數(shù)加 1
* @return
*/
Object next();
}
創(chuàng)建迭代器
import java.util.ArrayList;
import java.util.List;
/**
* Created by yangshuai in the 21:14 of 2016.06.30 .
* 男子高校人員信息迭代器
*/
public class ManIterator implements Iterator {
private List<People> list = new ArrayList<>();
private int index = 0;
public ManIterator(List<People> list) {
list.addAll(list);
}
@Override
public boolean hasNext() {
return index < list.size() && list.get(index) != null;
}
@Override
public Object next() {
return list.get(index++);
}
}
import java.util.ArrayList;
import java.util.List;
/**
* Created by yangshuai in the 21:24 of 2016.06.30 .
* 女子高校人員信息迭代器
*/
public class WomanIterator implements Iterator {
private List<People> list = new ArrayList<>();
private int index = 0;
public WomanIterator(List<People> list) {
this.list.addAll(list);
}
@Override
public boolean hasNext() {
return index < list.size() && list.get(index) != null;
}
@Override
public Object next() {
return list.get(index++);
}
}
創(chuàng)建容器接口
/**
* Created by yangshuai in the 21:29 of 2016.06.30 .
* 定義一個通用接口,用來返回容器,或者也可以進行添加刪除人員, 也可以更新人員信息(略)。
*/
public interface School {
void add(People people);
void Remove(People people);
/**
* 只有在使用的時候在創(chuàng)建容器對象
* @return
*/
Iterator iterator();
}
創(chuàng)建容器
import java.util.ArrayList;
import java.util.List;
/**
* Created by yangshuai in the 21:27 of 2016.06.30 .
*/
public class ManSchool implements School {
private List<People> list;
public ManSchool() {
list = new ArrayList<>();
}
@Override
public void add(People people) {
list.add(people);
}
@Override
public void Remove(People people) {
if (list.contains(people)) {
list.remove(people);
}
}
@Override
public Iterator iterator() {
return new ManIterator(list);
}
}
import java.util.ArrayList;
import java.util.List;
/**
* Created by yangshuai in the 21:27 of 2016.06.30 .
*/
public class WomanSchool implements School {
private List<People> list;
public WomanSchool() {
list = new ArrayList<>();
}
@Override
public void add(People people) {
list.add(people);
}
@Override
public void Remove(People people) {
if (list.contains(people)) {
list.remove(people);
}
}
@Override
public Iterator iterator() {
return new WomanIterator(list);
}
}
調(diào)用方法
/**
* Created by yangshuai in the 21:34 of 2016.06.30 .
* 遍歷男子高校和女子高校的信息就可以使用一種方法。
*/
public class Use {
public static void main(String []args) {
WomanSchool womanSchool = new WomanSchool();
womanSchool.add(new People("a", 11));
womanSchool.add(new People("b", 11));
womanSchool.add(new People("c", 11));
showSchoolPeopleInfo(womanSchool.iterator());
ManSchool manSchool = new ManSchool();
manSchool.add(new People("d", 11));
manSchool.add(new People("e", 11));
manSchool.add(new People("f", 11));
showSchoolPeopleInfo(womanSchool.iterator());
}
public static void showSchoolPeopleInfo(Iterator iterator) {
if (iterator.hasNext()) {
iterator.next().toString();
}
}
}
優(yōu)點
分離遍歷算法和容器。
缺點
增加了類文件。
12.模板方法模式
抽取公有方法到基類中,讓其他類都繼承這個基類,例如 BaseActiviy,你懂的,這里就不再舉例。
優(yōu)點
- 封裝了公用的代碼,易于維護更新;
- 可以自由重寫擴展公用方法,保留不變代碼。
缺點
代碼閱讀困難。那不怪我嘍,你要看不懂。
13.訪問者模式
一個對象有有多個互不關(guān)聯(lián)的方法,這些方法又被不同的對象調(diào)用,這個時候使用訪問者模式比較好。
下面以游客逛公園舉例,公園有熊貓和跳跳虎,年輕人與熊貓玩給跳跳虎喂食,老年人看看介紹就可以了:
創(chuàng)建訪問者
訪問者要對不同的元素有不同的訪問方式,給跳跳虎喂食,與熊貓玩耍,所以要區(qū)分開來:
/**
* Created by yangshuai in the 21:09 of 2016.07.04 .
* 訪問者接口,訪問每個動物。
*/
public interface Visitor {
void visit(Tigger tigger);
void visit(Panda panda);
}
創(chuàng)建元素接口或抽象類,定義被訪問對象
被訪問者要實現(xiàn) accept 接口,用來接收訪問者的訪問:
/**
* Created by yangshuai in the 21:00 of 2016.07.04 .
* 動物基類,有兩個屬性 名字和種類
*/
public abstract class Anim {
public String name;
public String variety;
public Anim(String name, String variety) {
this.name = name;
this.variety = variety;
}
/**
* 接受訪問者的訪問
* @param visitor
*/
protected abstract void accept(Visitor visitor);
}
創(chuàng)建具體的被訪問者
/**
* Created by yangshuai in the 21:11 of 2016.07.04 .
* 熊貓
*/
public class Panda extends Anim {
public Panda(String name) {
super(name, "吃竹子的");
}
@Override
protected void accept(Visitor visitor) {
visitor.visit(this);
}
/**
* 熊貓玩耍
* @param player
* @return
*/
public String playWith(String player) {
Log.d(name, "和" + player + "玩的超級開心吶");
return "玩的開心";
}
}
/**
* Created by yangshuai in the 21:10 of 2016.07.04 .
* 跳跳虎
*/
public class Tigger extends Anim{
public Tigger(String name) {
super(name, "吃肉的");
}
@Override
protected void accept(Visitor visitor) {
visitor.visit(this);
}
/**
* 老虎進食
* @param food
* @return
*/
public String eat(String food) {
Log.d(name, "eat :" + food);
return "吃的開心";
}
}
創(chuàng)建被訪問元素的集合
/**
* Created by yangshuai in the 21:25 of 2016.07.04 .
* 動物園,有三個熊貓,兩個跳跳虎
*/
public class Zoo {
private List<Anim> list = new LinkedList<>();
public Zoo() {
list.add(new Panda("小花"));
list.add(new Panda("小1"));
list.add(new Panda("小a"));
list.add(new Tigger("小妞"));
list.add(new Tigger("小BB"));
}
/**
* 開門營業(yè),訪問者訪問每個動物
* @param visitor
*/
public void openDoor(Visitor visitor) {
for (Anim anim : list) {
anim.accept(visitor);
}
}
}
創(chuàng)建具體的訪問者
/**
* Created by yangshuai in the 21:20 of 2016.07.04 .
* 老人只要知道動物的種類就可以了
*/
public class OldMan implements Visitor {
@Override
public void visit(Tigger tigger) {
Log.d("OldMan", tigger.variety);
}
@Override
public void visit(Panda panda) {
Log.d("OldMan", panda.variety);
}
}
/**
* Created by yangshuai in the 21:20 of 2016.07.04 .
* 年輕人不僅要知道動物的名字還要和動物互動
*/
public class YoungMan implements Visitor {
@Override
public void visit(Tigger tigger) {
Log.d("YoungMan", tigger.name + ":" + tigger.eat("food"));
}
@Override
public void visit(Panda panda) {
Log.d("YoungMan", panda.name + ":" + panda.playWith("Afra"));
}
}
使用方法
/**
* Created by yangshuai in the 21:28 of 2016.07.04 .
*/
public class IsTimeToPlay {
public static void main(String[] args) {
// 創(chuàng)建動物園
Zoo zoo = new Zoo();
// 創(chuàng)建老年訪問者
OldMan oldMan = new OldMan();
zoo.openDoor(oldMan);
// 創(chuàng)建青年訪問者
YoungMan youngMan = new YoungMan();
zoo.openDoor(youngMan);
}
}
優(yōu)點
上面的情景要是使用 if-else 的話,難以擴展和維護,甚至類型多的情況下會很復(fù)雜:
if 老年人
讀取動物介紹
else if 年輕人
if 跳跳虎
動物喂食
if 熊貓
動物玩
- 訪問者模式另各個角色分離;
- 擴展性良好,更靈活;
- 數(shù)據(jù)和操作解耦;
缺點
1.被訪問者修改了后,操作修改變更大;
2.為了對訪問的對象有不同的操作,而依賴了具體的類;
14.中間人模式
當多個對象的操作互相依賴,互相影響時,中間人模式是個很好的選擇。
接下來以拍電影舉例,導(dǎo)演喊開始,中間人跑去跟演員說導(dǎo)演喊開始啦,然后演員開始表演,演員突然笑場,要中間人跑去給導(dǎo)演說,演員笑場了,然后導(dǎo)演重新喊開始:
定義中間人抽象類,也可以是接口
/**
* Created by yangshuai in the 22:07 of 2016.07.05 .
* 中間人,跑腿的,每個人的狀態(tài)更新后都要去通知相關(guān)的人。
*/
public abstract class Mediator {
public abstract void updataState(People people);
}
定義互相影響的對象的抽象基類,也可以是接口
/**
* Created by yangshuai in the 22:07 of 2016.07.05 .
* 人的抽象類,可以是接口
*/
public abstract class People {
protected Mediator mediator;
public People(Mediator mediator) {
this.mediator = mediator;
}
}
創(chuàng)建具體的互相影響的對象
/**
* Created by yangshuai in the 22:13 of 2016.07.05 .
* 導(dǎo)演,用于喊 開始,然后演員開始演戲
*/
public class Director extends People {
public Director(Mediator mediator) {
super(mediator);
}
public void action() {
mediator.updataState(this);
}
}
/**
* Created by yangshuai in the 22:15 of 2016.07.05 .
* 演員,在導(dǎo)演喊開始后開始演戲,中間笑場了導(dǎo)演要重新喊開始。
*/
public class Player extends People {
public Player(Mediator mediator) {
super(mediator);
}
public void laughAload() {
mediator.updataState(this);
}
public void play() {
// 開始表演
}
}
創(chuàng)建具體的中間人
/**
* Created by yangshuai in the 22:17 of 2016.07.05 .
* 跑腿的就是中間人,負責(zé)通知導(dǎo)演或者演員狀態(tài)更新。
*/
public class Footwork extends Mediator {
private Player player;
private Director director;
public void setPlayer(Player player) {
this.player = player;
}
public void setDirector(Director director) {
this.director = director;
}
@Override
public void updataState(People people) {
if (people instanceof Director) { // 導(dǎo)演喊開始了,這里簡化了判斷
if (player != null) {
player.play();
}
} else if (people instanceof Player) { // 演員笑場了,這里簡化了判斷
if (director != null) {
director.action();
}
}
}
}
使用
/**
* Created by yangshuai in the 22:22 of 2016.07.05 .
*/
public class Room {
public static void main(String args[]) {
// 創(chuàng)建中間人,即跑腿的
Footwork mediator = new Footwork();
// 創(chuàng)建導(dǎo)演
Director director = new Director(mediator);
mediator.setDirector(director);
// 創(chuàng)建演員
Player player = new Player(mediator);
mediator.setPlayer(player);
// 導(dǎo)演喊開始了,然后中間人通知演員開始演戲
director.action();
// 演員笑場了,然后中間人通知導(dǎo)演重新喊開始
player.laughAload();
}
}
優(yōu)點
解耦復(fù)雜的依賴,清晰邏輯,降低復(fù)雜度,提高擴展性。
缺點
要是互相依賴的操作量少,中間人模式可能會導(dǎo)致代碼的邏輯結(jié)構(gòu)更加復(fù)雜化。
15.代理模式
當沒法去訪問一個對象時可以通過代理模式間接訪問。代理對象和被代理對象要有相同的接口。
以下以中午帶飯為例進行舉例:
創(chuàng)建代理接口(代理人和被代理人都要實現(xiàn))
/**
* Created by Afra55 on 2016.07.09 .
* 中午吃飯接口, 走路去飯店,購買自己喜歡的食物
*/
public interface IEat {
/**
* 走路去飯店
*/
void walk();
/**
* 選擇食物
*/
void choose();
/**
* 購買
*/
void buy();
}
創(chuàng)建懶人(被代理人)
/**
* Created by Afra55 on 2016.07.09 .
* 具體的中午吃飯的人
*/
public class Layzer implements IEat {
@Override
public void walk() {
System.out.println("走路去飯店");
}
@Override
public void choose() {
System.out.println("選擇食物");
}
@Override
public void buy() {
System.out.println("掏錢買");
}
}
靜態(tài)代理
創(chuàng)建代理人
/**
* Created by Afra55 on 2016.07.09 .
* 懶人懶得出去買飯,交給 Greater 去買,Greater 就是代理人
*/
public class Greater implements IEat {
private final IEat eater;
public Greater(IEat iEat) {
this.eater = iEat;
}
@Override
public void walk() {
eater.walk();
}
@Override
public void choose() {
eater.choose();
}
@Override
public void buy() {
eater.buy();
}
}
使用方法
/**
* Created by Afra55 on 2016.07.09 .
* 被代理人 通過 代理人 來完成一些列事情
*/
public class Main {
public static void main(String []args) {
// 被代理對象
IEat layzer = new Layzer();
// 代理人
IEat greater = new Greater(layzer);
greater.walk();
greater.choose();
greater.buy();
}
}
動態(tài)代理
動態(tài)代理即通過反射動態(tài)生成代理對象,在運行階段來決定被代理對象而不是編碼階段。在這里使用java提供的動態(tài)代理接口 InvocationHandler。
創(chuàng)建動態(tài)代理實現(xiàn)類
/**
* Created by Afra55 on 2016.07.09 .
* 動態(tài)代理
*/
public class DynamicProxy implements InvocationHandler {
private final Object object;
public DynamicProxy(Object o) {
this.object = o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(object, args);
}
}
使用
/**
* Created by Afra55 on 2016.07.09 .
* 被代理人 通過 代理人 來完成一些列事情
*/
public class Main {
public static void main(String []args) {
// 被代理對象
IEat layzer = new Layzer();
// 獲取 classloader
ClassLoader classLoader = Layzer.class.getClassLoader();
// 創(chuàng)建動態(tài)代理
DynamicProxy dynamicProxy = new DynamicProxy(layzer);
// 動態(tài)創(chuàng)建代理人,完全與被代理對象解耦,不必關(guān)心去代理誰,也不必創(chuàng)建代理人類
IEat greater = (IEat) Proxy.newProxyInstance(classLoader, new Class[]{IEat.class}, dynamicProxy);
greater.walk();
greater.choose();
greater.buy();
}
}
優(yōu)點
叼。
缺點
叼。
16.組合模式
如果一個整體能獨立出一部分模塊或功能時使用。例如,團隊和個人。
下面以社會舉例,社會由群眾組成,群眾由團隊組成,團隊由個人組成。
安全的組合模式
創(chuàng)建抽象基類
/**
* Created by Afra55 on 2016.07.12 .
* 抽象類,用于表示整個社會
*/
public abstract class Society {
protected String name;
public Society(String name) {
this.name = name;
}
public abstract void doSomething();
}
創(chuàng)建群眾
import java.util.ArrayList;
import java.util.List;
/**
* Created by Afra55 on 2016.07.12 .
* 社會由群體組成,群體是社會的具體實現(xiàn).
* 群體又由各個團隊組成.
*/
public class Mass extends Society {
/**
* 存儲各個團隊的容器
*/
private List<Society> societyList = new ArrayList<>();
public Mass(String name) {
super(name);
}
/**
* 添加團隊
* @param society 團隊
*/
public void addTeam(Society society) {
societyList.add(society);
}
/**
* 移除團隊
* @param society 團隊
*/
public void removeTeam(Society society) {
if (societyList.contains(society)) {
societyList.remove(society);
}
}
/**
* 獲取團隊數(shù)量
* @return 團隊的數(shù)量
*/
public int getTeamCount() {
return societyList.size();
}
/**
* 獲取團隊
* @param index 團隊索引
* @return
*/
public Society getTeam(int index) {
if (index < getTeamCount()) {
return societyList.get(index);
} else {
throw new IndexOutOfBoundsException("這個團隊不存在");
}
}
@Override
public void doSomething() {
System.out.println(name + "群眾是偉大的");
for (int i = 0 ; i< getTeamCount(); i++) {
getTeam(i).doSomething();
}
}
}
創(chuàng)建團隊
/**
* Created by Afra55 on 2016.07.12 .
* 個人組成了群眾,個人又有個人組成
*/
public class Team extends Society {
/**
* 存儲個人的容器
*/
private List<Society> societyList = new ArrayList<>();
public Team(String name) {
super(name);
}
/**
* 添加個人
* @param society 個人
*/
public void addPeople(Society society) {
societyList.add(society);
}
/**
* 移除個人
* @param society 個人
*/
public void removePeople(Society society) {
if (societyList.contains(society)) {
societyList.remove(society);
}
}
/**
* 獲取個人數(shù)量
* @return 個人的數(shù)量
*/
public int getPeopleCount() {
return societyList.size();
}
/**
* 獲取個人
* @param index 個人索引
* @return
*/
public Society getPeople(int index) {
if (index < getPeopleCount()) {
return societyList.get(index);
} else {
throw new IndexOutOfBoundsException("這個人不存在");
}
}
@Override
public void doSomething() {
System.out.println(name + "團隊是偉大的");
for (int i = 0 ; i< getPeopleCount(); i++) {
getPeople(i).doSomething();
}
}
}
創(chuàng)建個人
/**
* Created by Afra55 on 2016.07.12 .
* 個人組成了團隊,是整個社會的記事
*/
public class People extends Society {
public People(String name) {
super(name);
}
@Override
public void doSomething() {
System.out.println(name + "是偉大的");
}
}
使用
public class Main {
public static void main(String []args) {
// 創(chuàng)建個人
People afra55 = new People("Afra55");
People victor = new People("Victor");
People aaa = new People("AAA啊哈");
// 創(chuàng)建 java tema
Team javaTeam = new Team("Java");
javaTeam.addPeople(afra55);
// 創(chuàng)建 android team
Team androidTeam = new Team("Andrid");
androidTeam.addPeople(victor);
androidTeam.addPeople(aaa);
// 創(chuàng)建群眾
Mass mass = new Mass("西安");
mass.addTeam(javaTeam);
mass.addTeam(androidTeam);
mass.doSomething();
}
}
輸出:
西安群眾是偉大的
Java團隊是偉大的
Afra55是偉大的
Andrid團隊是偉大的
Victor是偉大的
AAA啊哈是偉大的
透明的組合模式
上述的例子中,不同的成員是有著不同的結(jié)構(gòu),在透明的組合模式中,他們都有著相同的結(jié)構(gòu),因而一些操作要放到內(nèi)部進行判斷。對于面向接口的編程,這個方法優(yōu)先考慮。
創(chuàng)建抽象基類
/**
* Created by Afra55 on 2016.07.12 .
* 抽象類,用于表示整個社會
*/
public abstract class Society {
protected String name;
public Society(String name) {
this.name = name;
}
/**
* 添加子模塊
* @param society
*/
public abstract void addSubSociety(Society society);
/**
* 移除子模塊
* @param society
*/
public abstract void removeSubSociety(Society society);
/**
* 獲取子模塊個數(shù)
* @return
*/
public abstract int getSubSocietyCount();
/**
* 獲取子模塊
* @param index 子模塊索引
* @return
*/
public abstract Society getSubSociety(int index);
public abstract void doSomething();
}
創(chuàng)建群眾
/**
* Created by Afra55 on 2016.07.12 .
* 社會由群體組成,群體是社會的具體實現(xiàn).
* 群體又由各個團隊組成.
*/
public class Mass extends Society {
/**
* 存儲各個團隊的容器
*/
private List<Society> societyList = new ArrayList<>();
public Mass(String name) {
super(name);
}
@Override
public void addSubSociety(Society society) {
societyList.add(society);
}
@Override
public void removeSubSociety(Society society) {
if (societyList.contains(society)) {
societyList.remove(society);
}
}
@Override
public int getSubSocietyCount() {
return societyList.size();
}
@Override
public Society getSubSociety(int index) {
if (index < getSubSocietyCount()) {
return societyList.get(index);
} else {
throw new IndexOutOfBoundsException("這個團隊不存在");
}
}
@Override
public void doSomething() {
System.out.println(name + "群眾是偉大的");
for (int i = 0 ; i< getSubSocietyCount(); i++) {
getSubSociety(i).doSomething();
}
}
}
創(chuàng)建團隊
/**
* Created by Afra55 on 2016.07.12 .
* 個人組成了群眾,個人又有個人組成
*/
public class Team extends Society {
/**
* 存儲個人的容器
*/
private List<Society> societyList = new ArrayList<>();
public Team(String name) {
super(name);
}
@Override
public void addSubSociety(Society society) {
societyList.add(society);
}
@Override
public void removeSubSociety(Society society) {
if (societyList.contains(society)) {
societyList.remove(society);
}
}
@Override
public int getSubSocietyCount() {
return societyList.size();
}
@Override
public Society getSubSociety(int index) {
if (index < getSubSocietyCount()) {
return societyList.get(index);
} else {
throw new IndexOutOfBoundsException("這個人不存在");
}
}
@Override
public void doSomething() {
System.out.println(name + "團隊是偉大的");
for (int i = 0 ; i< getSubSocietyCount(); i++) {
getSubSociety(i).doSomething();
}
}
}
創(chuàng)建個人
/**
* Created by Afra55 on 2016.07.12 .
* 個人組成了團隊,是整個社會的記事
*/
public class People extends Society {
public People(String name) {
super(name);
}
@Override
public void addSubSociety(Society society) {
throw new UnsupportedOperationException("個人是個個體,沒有子模塊");
}
@Override
public void removeSubSociety(Society society) {
throw new UnsupportedOperationException("個人是個個體,沒有子模塊");
}
@Override
public int getSubSocietyCount() {
throw new UnsupportedOperationException("個人是個個體,沒有子模塊");
}
@Override
public Society getSubSociety(int index) {
throw new UnsupportedOperationException("個人是個個體,沒有子模塊");
}
@Override
public void doSomething() {
System.out.println(name + "是偉大的");
}
}
使用
public class Main {
public static void main(String []args) {
// 創(chuàng)建個人
People afra55 = new People("Afra55");
People victor = new People("Victor");
People aaa = new People("AAA啊哈");
// 創(chuàng)建 java tema
Team javaTeam = new Team("Java");
javaTeam.addSubSociety(afra55);
// 創(chuàng)建 android team
Team androidTeam = new Team("Andrid");
androidTeam.addSubSociety(victor);
androidTeam.addSubSociety(aaa);
// 創(chuàng)建群眾
Mass mass = new Mass("西安");
mass.addSubSociety(javaTeam);
mass.addSubSociety(androidTeam);
mass.doSomething();
}
}
輸出:
西安群眾是偉大的
Java團隊是偉大的
Afra55是偉大的
Andrid團隊是偉大的
Victor是偉大的
AAA啊哈是偉大的
優(yōu)點
不必關(guān)心對象是個集合還是個體,新增各種成員都很方便,只要繼承基類實現(xiàn)抽象方法即可,不用修改現(xiàn)有的類。
組合模式可以生成復(fù)雜的樹形結(jié)構(gòu),對各個節(jié)點的操作統(tǒng)一而且簡單。
缺點
新增的成員局限于基類,想要統(tǒng)一新功能就要修改基類,所有的繼承基類的類都會進行修改。如果不修改基類,依賴類型,則會對類型進行判斷,增加了代碼復(fù)雜度。
17.適配器模式
當接口不兼容而去兼容接口,或者建立一個可以重復(fù)被不同對象使用的類,或者統(tǒng)一輸出接口,設(shè)配器模式很合適。
下面以藍牙耳機舉例,假設(shè)某款藍牙耳機支持藍牙4.1的設(shè)備不支持4.0的藍牙設(shè)備,現(xiàn)在有個藍牙4.0的手機連接藍牙耳機,需要把藍牙耳機的藍牙設(shè)備版本4.1兼容4.0。
創(chuàng)建接口
/**
* Created by Afra55 on 2016.07.13 .
* 藍牙版本接口
*/
public interface IVersion {
double getVersion();
}
需要適配的類
/**
* Created by Afra55 on 2016.07.13 .
* 藍牙耳機支持的藍牙版本是4.1,不支持4.0
*/
public class BluetoothHeadset implements IVersion {
@Override
public double getVersion() {
return 4.1;
}
}
類適配器模式
創(chuàng)建適配器
/**
* Created by Afra55 on 2016.07.13 .
* 藍牙適配器吧藍牙耳機的藍牙版本轉(zhuǎn)換為4.0,以便連接手機。
*/
public class BluetoothAdapter extends BluetoothHeadset {
@Override
public double getVersion() {
return 4.0;
}
}
使用
public class Main {
public static void main(String []args) {
BluetoothAdapter bluetoothAdapter = new BluetoothAdapter();
System.out.println(bluetoothAdapter.getVersion());
}
}
對象適配器模式
創(chuàng)建適配器
/**
* Created by Afra55 on 2016.07.13 .
* 藍牙適配器吧藍牙耳機的藍牙版本轉(zhuǎn)換為4.0,以便連接手機。
*/
public class BluetoothAdapter implements IVersion {
private final BluetoothHeadset bluetoothHeadset;
public BluetoothAdapter(BluetoothHeadset bluetoothHeadset) {
this.bluetoothHeadset = bluetoothHeadset;
}
public double getOriginVersion() {
return bluetoothHeadset.getVersion();
}
@Override
public double getVersion() {
// 在這里進行藍牙版本轉(zhuǎn)換
return 4.0;
}
}
使用
public class Main {
public static void main(String []args) {
BluetoothHeadset bluetoothHeadset = new BluetoothHeadset();
BluetoothAdapter bluetoothAdapter = new BluetoothAdapter(bluetoothHeadset);
System.out.println("藍牙耳機支持的版本: " + bluetoothAdapter.getOriginVersion());
System.out.println("藍牙耳機適配后的版本: " + bluetoothAdapter.getVersion());
}
}
優(yōu)點
良好的復(fù)用性和擴展性。
缺點
過多的使用適配器,會造成代碼的復(fù)雜度提升。
18.裝飾模式
要透明且動態(tài)的擴展類的功能時,裝飾模式是個好的選擇。
比如,給人穿不同的衣服,人的 dress 方法是 準備穿衣,現(xiàn)在要擴展功能,穿各種各樣的衣服:
創(chuàng)建人的抽象基類,也可以是接口
/**
* Created by Afra55 on 2016.07.14 .
* 人的抽象基類,有個穿衣服的抽象方法
*/
public abstract class People {
/**
* 穿衣服
*/
public abstract void dressed();
}
人的實現(xiàn)類
/**
* Created by Afra55 on 2016.07.14 .
* 人的實現(xiàn)類
*/
public class Man extends People {
private String name;
public Man(String name) {
this.name = name;
}
public String getName() {
return name;
}
/**
* 只有準備衣服的功能
*/
@Override
public void dressed() {
System.out.println(getName() +" 準備衣服");
}
}
創(chuàng)建衣服的抽象基類,這里偷懶了
/**
* Created by Afra55 on 2016.07.14 .
* 衣服基類,保持了一個 people 的引用
*/
public class Cloth extends People {
protected People people;
public Cloth(People people) {
this.people = people;
}
@Override
public void dressed() {
people.dressed();
}
}
創(chuàng)建裙子
/**
* Created by Afra55 on 2016.07.14 .
* 裙子
*/
public class Skirt extends Cloth {
public Skirt(People people) {
super(people);
}
@Override
public void dressed() {
super.dressed();
dressSkirt();
}
private void dressSkirt() {
System.out.println("穿連衣裙");
}
}
創(chuàng)建西服
/**
* Created by Afra55 on 2016.07.14 .
* 西服
*/
public class Suit extends Cloth {
public Suit(People people) {
super(people);
}
@Override
public void dressed() {
super.dressed();
dressSuit();
}
private void dressSuit() {
System.out.println("穿上西服");
}
}
使用
public class Main {
public static void main(String []args) {
// 創(chuàng)建了一個人
People you = new Man("Victoor");
// 創(chuàng)建西服,持有 you 對象
Cloth suit = new Suit(you);
suit.dressed();
// 創(chuàng)建連衣裙,持有 you 對象
Cloth skirt = new Skirt(you);
skirt.dressed();
}
}
優(yōu)點
動態(tài)擴展對象的功能。
缺點
19.享元模式
當有大量的重復(fù)對象出現(xiàn),每次調(diào)用都會去new 一個新的對象,這個對象并沒有什么改變,這個時候使用享元模式較好,可以避免創(chuàng)建多個對象。也可以充當緩沖池使用。
以下以天氣查詢舉例,每天都會有人通過日期查詢天氣,日期相同返回的結(jié)果就相同,當有數(shù)以百萬計的人查詢一個相同的日期時,每次創(chuàng)建新的信息對象會對系統(tǒng)造成很大的負擔(dān),像這類重復(fù)的對象,可以使用緩沖池來讀取緩存里的對象:
創(chuàng)建接口
/**
* Created by Afra55 on 2016.07.15 .
* 天氣接口,只獲取天氣情況
*/
public interface IWeather {
String getWeatherItem();
}
創(chuàng)建實現(xiàn)類
/**
* Created by Afra55 on 2016.07.15 .
* 天氣的實現(xiàn)類
*/
public class WeatherItem implements IWeather {
private String date;
public WeatherItem(String date) {
this.date = date;
}
@Override
public String getWeatherItem() {
String result = "未查到信息";
// 請忽略偷懶的代碼
int random = new Random().nextInt(100);
switch (date) {
case "今天":
result = "晴天 " + random + "攝氏度";
break;
case "明天":
result = "小雨 " + random + "攝氏度";
break;
case "后天":
result = "陰天 " + random + "攝氏度";
break;
}
return result;
}
}
創(chuàng)建享元工廠
/**
* Created by Afra55 on 2016.07.15 .
* 享元模式的體現(xiàn),減少重復(fù)對象的存在,讓同類對象多次復(fù)用
*/
public class WeatherFactory {
// 使用 map 容器來存儲 天氣 對象,以便在下一次查詢時只拿緩存中的
private static Map<String, IWeather> weatherMap = new ConcurrentHashMap<>();
public static IWeather getWeatherInfo(String date) {
if (weatherMap.containsKey(date)) { // 使用緩存的
return weatherMap.get(date);
} else {
IWeather weather = new WeatherItem(date); // 創(chuàng)建新對象
weatherMap.put(date, weather);
return weather;
}
}
}
使用舉例
public class Main {
public static void main(String []args) {
for (int i = 0 ;i < 100; i++) {
System.out.println(WeatherFactory.getWeatherInfo("今天").getWeatherItem());
System.out.println(WeatherFactory.getWeatherInfo("明天").getWeatherItem());
System.out.println(WeatherFactory.getWeatherInfo("后天").getWeatherItem());
}
}
}
優(yōu)點
減少重復(fù)類的創(chuàng)建,降低內(nèi)存使用。
缺點
邏輯復(fù)雜,代碼復(fù)雜,從緩沖區(qū)中讀取從而增加了讀取時間。
20.外觀模式
當對一個功能模塊進行封裝后,這個功能模塊的調(diào)用變成了一個簡單接口,使用這個功能時不必關(guān)心他的內(nèi)部操作,不去管功能模塊內(nèi)部的修改升級維護等,這種封裝的行為就是外觀模式。
比如 人能 聽說讀寫, 吃喝拉撒,把功能的調(diào)用 都 放在了 人這個類中通過八個簡單的接口實現(xiàn),每次調(diào)用,不會去管他的內(nèi)部實現(xiàn),只要實現(xiàn)功能即可。就跟 Android 去調(diào)用第三方 SDK 一樣,看不到內(nèi)部實現(xiàn),只能調(diào)用封裝好的簡單接口。
優(yōu)點
隱藏了功能細節(jié),能夠靈活的去改變功能模塊,并且讓功能易于使用。
缺點
當業(yè)務(wù)變更,可能要直接去修改功能模塊的細節(jié)。更能的增多,接口也會增多,造成了用戶學(xué)習(xí)成本的提升。
21.橋接模式
當類存在兩個獨立的功能,而且都要進行擴展時,使用橋接模式。
下面以奶茶為例,奶茶有 大杯加糖,大杯加鹽,小杯加糖,小杯加鹽。大杯和小杯屬于杯子大小功能的擴展,加鹽和加糖屬于添加劑功能的擴展,不管誰變化,都沒有交集。
創(chuàng)建實現(xiàn)部分的抽象基類
/**
* Created by Afra55 on 2016.07.15 .
* 添加劑
*/
public abstract class Additive {
public abstract String getAdditive();
}
創(chuàng)建實現(xiàn)部分具體的實現(xiàn)
public class Salt extends Additive {
@Override
public String getAdditive() {
// 具體的實現(xiàn)
return "加鹽";
}
}
public class Sugar extends Additive {
@Override
public String getAdditive() {
// 具體的實現(xiàn)
return "加糖";
}
}
創(chuàng)建抽象部分的抽象基類
/**
* Created by Afra55 on 2016.07.15 .
* 奶茶抽象基類
*/
public abstract class MilkyTea {
protected Additive additive;
public MilkyTea(Additive additive) {
this.additive = additive;
}
// 由子類決定奶茶的創(chuàng)建
public abstract void make();
}
創(chuàng)建抽象部分的子類
/**
* Created by Afra55 on 2016.07.15 .
* 大杯奶茶
*/
public class BigMildyTea extends MilkyTea{
public BigMildyTea(Additive additive) {
super(additive);
}
@Override
public void make() {
// 通過調(diào)用實現(xiàn)部分的方法來實現(xiàn)功能
System.out.println("大杯的" + additive.getAdditive() + "奶茶");
}
}
/**
* Created by Afra55 on 2016.07.15 .
* 小杯奶茶
*/
public class SmallMildyTea extends MilkyTea{
public SmallMildyTea(Additive additive) {
super(additive);
}
@Override
public void make() {
// 通過調(diào)用實現(xiàn)部分的方法來實現(xiàn)功能
System.out.println("小杯的" + additive.getAdditive() + "奶茶");
}
}
使用
public class Main {
public static void main(String []args) {
BigMildyTea bigMildyTea = new BigMildyTea(new Sugar());
bigMildyTea.make();
BigMildyTea bigMildyTea1 = new BigMildyTea(new Salt());
bigMildyTea1.make();
SmallMildyTea smallMildyTea = new SmallMildyTea(new Sugar());
smallMildyTea.make();
SmallMildyTea smallMildyTea1 = new SmallMildyTea(new Salt());
smallMildyTea1.make();
}
}
輸出:
大杯的加糖奶茶
大杯的加鹽奶茶
小杯的加糖奶茶
小杯的加鹽奶茶
優(yōu)點
分離抽象與實現(xiàn),靈活的擴展,對使用的透明。
缺點
不容易設(shè)計,經(jīng)驗尚淺,就是想不到怎么做(笑臉)。
22.抽象工廠模式
先復(fù)習(xí)工廠模式先。
一個對象族有相同的約束時,可以使用工廠模式。
看下面的例子, 鞋子 A3 和 B3 就是個對象族,他們的相同約束是材質(zhì)制作和浸染顏色:
抽象工廠類
/**
* Created by Afra55 on 2016.07.19 .
* 鞋子抽象工廠類,用于制造鞋子,這里只定義了兩種,用于浸染顏色和制造材質(zhì)。
*/
public abstract class ShoeFactory {
/**
* 制作材質(zhì)
* @return 材質(zhì)
*/
public abstract ITexture createTexture();
/**
* 浸染顏色
* @return 顏色
*/
public abstract IColor changeColor();
}
材質(zhì)相關(guān)
/**
* Created by Afra55 on 2016.07.19 .
* 材質(zhì)接口
*/
public interface ITexture {
void texture();
}
public class CowhideTexture implements ITexture {
@Override
public void texture() {
System.out.println("制作牛皮材質(zhì)");
}
}
public class DecorativeRndTexture implements ITexture {
@Override
public void texture() {
System.out.println("制作花皮材質(zhì)");
}
}
顏色相關(guān)
/**
* Created by Afra55 on 2016.07.19 .
* 顏色接口
*/
public interface IColor {
void color();
}
public class GreenColor implements IColor {
@Override
public void color() {
System.out.println("浸染綠色");
}
}
public class RedColor implements IColor {
@Override
public void color() {
System.out.println("浸染紅色");
}
}
具體工廠類
/**
* Created by Afra55 on 2016.07.19 .
* 綠鞋,牛皮材質(zhì)
*/
public class A2Factory extends ShoeFactory {
@Override
public ITexture createTexture() {
return new CowhideTexture();
}
@Override
public IColor changeColor() {
return new GreenColor();
}
public A2Factory create() {
System.out.println("開始制作 A2 鞋子:");
createTexture().texture();
changeColor().color();
System.out.println("A2 鞋子制作完成。。。");
return this;
}
}
/**
* Created by Afra55 on 2016.07.19 .
* 紅鞋,花皮材質(zhì)
*/
public class B3Factory extends ShoeFactory {
@Override
public ITexture createTexture() {
return new DecorativeRndTexture();
}
@Override
public IColor changeColor() {
return new RedColor();
}
public B3Factory create() {
System.out.println("開始制作 B3 鞋子:");
createTexture().texture();
changeColor().color();
System.out.println("B3 鞋子制作完成。。。");
return this;
}
}
使用
public class Main {
public static void main(String []args) {
A2Factory a2Factory = new A2Factory();
a2Factory.create();
B3Factory b3Factory = new B3Factory();
b3Factory.create();
}
}
輸出:
開始制作 A2 鞋子:
制作牛皮材質(zhì)
浸染綠色
A2 鞋子制作完成。。。
開始制作 B3 鞋子:
制作花皮材質(zhì)
浸染紅色
B3 鞋子制作完成。。。
優(yōu)點
分離接口與實現(xiàn)。
缺點
類文件的增加。
每次修改功能,修改抽象工廠,具體工廠都會被修改。
23.解釋器模式
解釋器模式使用較少,主要功能就是解釋,例如 1 # 3 其中把特殊字符 # 解釋成 加號,即 1 # 3 就是 1 + 3,這種行為就是解釋器。
接口
/**
* Created by Afra55 on 2016.07.19 .
* 抽象表達式,定義抽象的解釋方法
*/
public abstract class AbstractExpression {
public abstract void explain();
}
具體實現(xiàn)
/**
* Created by Afra55 on 2016.07.19 .
* 符號解釋器,例如 解釋 # 為 +
*/
public class CharExpression extends AbstractExpression {
@Override
public void explain() {
}
}
/**
* Created by Afra55 on 2016.07.19 .
* 數(shù)字解釋器,例如 1 3,非符號類
*/
public class NumExpression extends AbstractExpression {
@Override
public void explain() {
}
}
優(yōu)點
擴展方便靈活。只需要增加相應(yīng)解釋器即可。
缺點
對于過于繁瑣的內(nèi)容進行解釋,會造成解釋器混亂繁瑣。解釋器要酌情使用。
面向?qū)ο蟮牧蠡驹瓌t回顧
單一職責(zé)原則 S
如題。
開閉原則 O
當功能需求變化時,盡量通過擴展來實現(xiàn)功能,從而避免修改原有代碼。
里氏替換原則 L
依賴繼承和多態(tài)。可以用父類替換子類,而不出錯,不必知道是父類還是子類。關(guān)鍵詞 抽象。
接口隔離原則 I
盡量少的暴露接口,只提供對應(yīng)功能的接口。
依賴倒置原則 D
實現(xiàn)類之間通過抽象進行依賴。即由父類抽象替換子類實現(xiàn),不必關(guān)心實現(xiàn)細節(jié)。
以上通常稱為 SOLID 原則。
迪米特原則 LOD
一個對象對其他對象應(yīng)該有最少的了解,只知道相應(yīng)依賴的方法即可,不關(guān)心具體實現(xiàn)和其他方法。
總結(jié)
面向接口的編程。