新聞中心
前言
本文將結(jié)合實(shí)際談?wù)?3種設(shè)計(jì)模式,每種設(shè)計(jì)模式涉及

站在用戶的角度思考問題,與客戶深入溝通,找到青岡網(wǎng)站設(shè)計(jì)與青岡網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:成都做網(wǎng)站、成都網(wǎng)站建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名注冊(cè)、網(wǎng)站空間、企業(yè)郵箱。業(yè)務(wù)覆蓋青岡地區(qū)。
- 定義:抽象化的定義與通俗的描述,盡量說明清楚其含義與應(yīng)用場景
- 示例:如果項(xiàng)目中有使用過該模式,則會(huì)給出項(xiàng)目中的代碼,否則會(huì)給出盡可能簡單好理解的java代碼
- Android:該設(shè)計(jì)模式在Android源碼框架中哪些地方有使用到
- 重構(gòu):項(xiàng)目中是否存在可以用該模式進(jìn)行重構(gòu)的地方,如果有會(huì)給出重構(gòu)前與重構(gòu)后的代碼或者思路
用這種方式進(jìn)行介紹設(shè)計(jì)模式,旨在結(jié)合每天都在接觸的Android實(shí)際項(xiàng)目開發(fā)更好地理解設(shè)計(jì)模式,拉近與設(shè)計(jì)模式的距離,同時(shí)在實(shí)際開發(fā)與重構(gòu)中,思考可以應(yīng)用的重構(gòu)手段與設(shè)計(jì)模式,既能保證寫出復(fù)用性與可靠性更高的代碼,也是對(duì)如何利用重構(gòu)與設(shè)計(jì)模式這兩大支柱進(jìn)行優(yōu)雅編程的最佳實(shí)踐與總結(jié)。
同時(shí)一次性以這種方式介紹23種設(shè)計(jì)模式,也是出于既然要使用一個(gè)模式,那么就應(yīng)該要先知道這么一個(gè)模式的想法,四人幫的《設(shè)計(jì)模式》也是對(duì)經(jīng)驗(yàn)的總結(jié),但是有巨人托著你上去,又何必自己再摸黑造梯子。
重構(gòu)不是本章的重點(diǎn),因?yàn)檫@也是一個(gè)非常大的話題,這邊只討論實(shí)際項(xiàng)目中是否有存在一些能用設(shè)計(jì)模式進(jìn)行改善的地方。
關(guān)于重構(gòu),這邊也有寫了一篇博文 重構(gòu):改善既有代碼的設(shè)計(jì) ,基本列舉了《重構(gòu):改善既有代碼的設(shè)計(jì)》中的各項(xiàng)要點(diǎn),后續(xù)還會(huì)繼續(xù)將《重構(gòu)》中的手法與設(shè)計(jì)模式應(yīng)用到實(shí)際項(xiàng)目中,有所總結(jié)之后會(huì)再寫幾篇實(shí)際應(yīng)用的博文。
簡介
設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 毫無疑問,設(shè)計(jì)模式于己于他人于系統(tǒng)都是多贏的,設(shè)計(jì)模式使代碼編制真正工程化,設(shè)計(jì)模式是軟件工程的基石,如同大廈的一塊塊磚石一樣。項(xiàng)目中合理的運(yùn)用設(shè)計(jì)模式可以完美的解決很多問題,每種模式在現(xiàn)在中都有相應(yīng)的原理來與之對(duì)應(yīng),每一個(gè)模式描述了一個(gè)在我們周圍不斷重復(fù)發(fā)生的問題,以及該問題的核心解決方案,這也是它能被廣泛應(yīng)用的原因。
六大原則
單一職責(zé)原則
單一原則很簡單,就是將一組相關(guān)性很高的函數(shù)、數(shù)據(jù)封裝到一個(gè)類中。換句話說,一個(gè)類應(yīng)該有職責(zé)單一。
開閉原則
開閉原則理解起來也不復(fù)雜,就是一個(gè)類應(yīng)該對(duì)于擴(kuò)展是開放的,但是對(duì)于修改是封閉的。在一開始編寫代碼時(shí),就應(yīng)該注意盡量通過擴(kuò)展的方式實(shí)現(xiàn)新的功能,而不是通過修改已有的代碼實(shí)現(xiàn),否則容易破壞原有的系統(tǒng),也可能帶來新的問題,如果發(fā)現(xiàn)沒辦法通過擴(kuò)展來實(shí)現(xiàn),應(yīng)該考慮是否是代碼結(jié)構(gòu)上的問題,通過重構(gòu)等方式進(jìn)行解決。
里氏替換原則
所有引用基類的地方必須能透明地使用其子類對(duì)象。本質(zhì)上就是說要好好利用繼承和多態(tài),從而以父類的形式來聲明變量(或形參),為變量(或形參)賦值任何繼承于這個(gè)父類的子類。
依賴倒置原則
依賴倒置主要是實(shí)現(xiàn)解耦,使得高層次的模塊不依賴于低層次模塊的具體實(shí)現(xiàn)細(xì)節(jié)。怎么去理解它呢,我們需要知道幾個(gè)關(guān)鍵點(diǎn):
- 高層模塊不應(yīng)該依賴底層模塊(具體實(shí)現(xiàn)),二者都應(yīng)該依賴其抽象(抽象類或接口)
- 抽象不應(yīng)該依賴細(xì)節(jié)
- 細(xì)節(jié)應(yīng)該依賴于抽象
在我們用的Java語言中,抽象就是指接口或者抽象類,二者都是不能直接被實(shí)例化;細(xì)節(jié)就是實(shí)現(xiàn)類,實(shí)現(xiàn)接口或者繼承抽象類而產(chǎn)生的類,就是細(xì)節(jié)。使用Java語言描述就是:各個(gè)模塊之間相互傳遞的參數(shù)聲明為抽象類型,而不是聲明為具體的實(shí)現(xiàn)類;
接口隔離原則
類之間的依賴關(guān)系應(yīng)該建立在最小的接口上。其原則是將非常龐大的、臃腫的接口拆分成更小的更具體的接口。
迪米特原則
一個(gè)對(duì)象應(yīng)該對(duì)其他的對(duì)象有最少的了解.
假設(shè)類A實(shí)現(xiàn)了某個(gè)功能,類B需要調(diào)用類A的去執(zhí)行這個(gè)功能,那么類A應(yīng)該只暴露一個(gè)函數(shù)給類B,這個(gè)函數(shù)表示是實(shí)現(xiàn)這個(gè)功能的函數(shù),而不是讓類A把實(shí)現(xiàn)這個(gè)功能的所有細(xì)分的函數(shù)暴露給B。
設(shè)計(jì)模式
單例模式
定義
確保單例類只有一個(gè)實(shí)例,并且這個(gè)單例類提供一個(gè)函數(shù)接口讓其他類獲取到這個(gè)唯一的實(shí)例。
如果某個(gè)類,創(chuàng)建時(shí)需要消耗很多資源,即new出這個(gè)類的代價(jià)很大;或者是這個(gè)類占用很多內(nèi)存,如果創(chuàng)建太多這個(gè)類實(shí)例會(huì)導(dǎo)致內(nèi)存占用太多。上述情況下就應(yīng)該使用單例模式
實(shí)際應(yīng)用
// 單例對(duì)象
private static AdvertPresenter mInstance;
/** * 私有化構(gòu)造函數(shù) */
private AdvertPresenter(){
}
/** * 獲取AdvertPresenter實(shí)例 * @return */
public static AdvertPresenter getInstance() {
if (mInstance == null) {
synchronized (AdvertPresenter.class) {
if (mInstance == null) {
mInstance = new AdvertPresenter();
}
}
}
return mInstance;
}Android
//獲取WindowManager服務(wù)引用 WindowManager wm = (WindowManager)getSystemService(getApplication().WINDOW_SERVICE);
其內(nèi)部就是通過單例的方式持有一個(gè)WindowManager并返回這個(gè)對(duì)象
重構(gòu)
項(xiàng)目中存在多次使用Random與Gson的操作,可以將Random與Gson對(duì)象封裝成單例進(jìn)行使用
建造者模式
定義
將一個(gè)復(fù)雜對(duì)象的構(gòu)造與它的表示分離,使得同樣的構(gòu)造過程可以創(chuàng)建不同的表示。
主要是在創(chuàng)建某個(gè)對(duì)象時(shí),需要設(shè)定很多的參數(shù)(通過setter方法),但是這些參數(shù)必須按照某個(gè)順序設(shè)定,或者是設(shè)置步驟不同會(huì)得到不同結(jié)果。
示例
各類自定義Dialog
Android
AlertDialog.Builer builder=new AlertDialog.Builder(context);
builder.setIcon(R.drawable.icon)
.setTitle("title")
.setMessage("message")
.setPositiveButton("Button1",
new DialogInterface.OnclickListener(){
public void onClick(DialogInterface dialog,int whichButton){
setTitle("click");
}
})
.create()
.show();重構(gòu)
暫無
原型模式
定義
用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并通過拷貝這些原型創(chuàng)建新的對(duì)象。
可以在類的屬性特別多,但是又要經(jīng)常對(duì)類進(jìn)行拷貝的時(shí)候可以用原型模式,這樣代碼比較簡潔,而且比較方便。
拷貝時(shí)要注意淺拷貝與深拷貝
示例
private HashMap getClonePointMap(Map map) {
HashMap clone = new HashMap<>();
if (map != null) {
Iterator iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
String key = (String) entry.getKey();
PointBean pointBean = (PointBean) entry.getValue();
if (pointBean != null) {
//遍歷map并將克隆對(duì)象放到新的map中
clone.put(key, pointBean.clone());
} else {
clone.put(key, null);
}
}
}
return clone;
}Android
Intent intent = new Intent(Intent.ACTION_SENDTO, uri); //克隆副本 Intent copyIntent=(Intetn)shareIntent.clone();
重構(gòu)
如果存在逐一去除某個(gè)對(duì)象的各項(xiàng)參數(shù)值,轉(zhuǎn)而賦值給另一個(gè)對(duì)象身上時(shí),便可使用原型模式
工廠模式
簡單工廠模式
定義
建立一個(gè)工廠(一個(gè)函數(shù)或一個(gè)類方法)來制造新的對(duì)象。
示例
public static Operation createOperate(string operate) {
Operation oper = null;
switch (operate)
{
case "+":
{
oper = new OperationAdd();
break;
}
case "-":
{
oper = new OperationSub();
break;
}
case "*":
{
oper = new OperationMul();
break;
}
case "/":
{
oper = new OperationDiv();
break;
}
}
return oper;
}
}Android
public Object getSystemService(String name) {
if (getBaseContext() == null) {
throw new IllegalStateException("System services not available to Activities before onCreate()");
}
//........
if (WINDOW_SERVICE.equals(name)) {
return mWindowManager;
} else if (SEARCH_SERVICE.equals(name)) {
ensureSearchManager();
return mSearchManager;
}
//.......
return super.getSystemService(name);
}在getSystemService方法中就是用到了簡單工廠模式,根據(jù)傳入的參數(shù)決定創(chuàng)建哪個(gè)對(duì)象,由于這些對(duì)象以單例模式提前創(chuàng)建好了,所以此處不用new了,直接把單例返回就好。
重構(gòu)
//重構(gòu)前
public class AdvertPresenter {
...
private void initAdvertManager() {
String[] platforms = mAdConfig.getAllPlatforms();
if (platforms != null && platforms.length > 0) {
int platformSize = platforms.length;
for (int i = 0; i < platformSize; i++) {
String platform = platforms[i];
if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_FACEBOOK)) {
FacebookAdvertManager fbAdManager = new FacebookAdvertManager();
mAdvertManager.put(AdvertConstant.AD_PLATFORM_FACEBOOK, fbAdManager);
} else if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_ADMOB)) {
AdMobAdvertManager adMobAdvertManager = new AdMobAdvertManager();
mAdvertManager.put(AdvertConstant.AD_PLATFORM_ADMOB, adMobAdvertManager);
} else if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_MOPUB)) {
MopubAdvertManager mopubAdvertManager = new MopubAdvertManager();
mAdvertManager.put(AdvertConstant.AD_PLATFORM_MOPUB, mopubAdvertManager);
} else if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_ADX)) {
AdxAdvertManager mopubAdvertManager = new AdxAdvertManager();
mAdvertManager.put(AdvertConstant.AD_PLATFORM_ADX, mopubAdvertManager);
}
}
}
}
...
}
//重構(gòu)后
public class BaseAdvertManager {
...
public static BaseAdvertManager create(String platform) {
if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_FACEBOOK)) {
return new FacebookAdvertManager();
} else if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_MOPUB)) {
return new MopubAdvertManager();
} else if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_ADX)) {
return new AdxAdvertManager();
} else if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_ADMOB)) {
return new AdMobAdvertManager();
} else {
***return new NullAdvertManager();***//引入NULL對(duì)象
}
}
...
}
public class AdvertPresenter {
...
private void initAdvertManager() {
String[] platforms = mAdConfig.getAllPlatforms();
if (platforms != null && platforms.length > 0) {
int platformSize = platforms.length;
for (int i = 0; i < platformSize; i++) {
String platform = platforms[i];
mAdvertManager.put(platform, BaseAdvertManager.create(platform));
}
}
}
...
}工廠方法模式
定義
是定義一個(gè)創(chuàng)建產(chǎn)品對(duì)象的工廠接口,讓其子類決定實(shí)例化哪一個(gè)類,將實(shí)際創(chuàng)建工作推遲到子類當(dāng)中。
示例
public abstract class Product {
public abstract void method();
}
public class ConcreteProduct extends Prodect {
public void method(){
System.out.println("我是具體產(chǎn)品!");
}
}
public abstract class Factory{
public abstract Product createProduct();
}
public class ConcreteFactory extends Factory{
public Product createProduct(){
return new ConcreteProductA();
}
}Android
我們?cè)陂_發(fā)中會(huì)用到很多數(shù)據(jù)結(jié)構(gòu),比如ArrayList,HashMap等。我們先來看下Java中Collection部分的類集框架的簡要UML圖。
我們知道Iterator是迭代器,用來遍歷一個(gè)集合中的元素。而不同的數(shù)據(jù)結(jié)構(gòu)遍歷的方式是不一樣的,所以迭代器的實(shí)現(xiàn)也是不同的。使用工廠方法模式將迭代器的具體類型延遲到具體容器類中,比較靈活,容易擴(kuò)展。
public interface Iterable {
/** * Returns an iterator over elements of type {@code T}. * * @return an Iterator. */
Iterator iterator();
//省略部分代碼
}List和Set繼承自Collection接口,Collection接口繼承于Iterable接口。所以List和Set接口也需要繼承并實(shí)現(xiàn)Iterable中的iterator()方法。然后我們常用的兩個(gè)間接實(shí)現(xiàn)類ArrayList和HashSet中的iterator方法就給我們具體構(gòu)造并返回了一個(gè)迭代器對(duì)象。
我們找到ArrayList類,查看iterator方法的實(shí)現(xiàn)。
@Override
public Iterator iterator() {
return new ArrayListIterator();
}ArrayListIterator類型定義如下:
private class ArrayListIterator implements Iterator {
/** Number of elements remaining in this iteration */
private int remaining = size;
/** Index of element that remove() would remove, or -1 if no such elt */
private int removalIndex = -1;
/** The expected modCount value */
private int expectedModCount = modCount;
public boolean hasNext() {
return remaining != 0;
}
@SuppressWarnings("unchecked") public E next() {
ArrayList ourList = ArrayList.this;
int rem = remaining;
if (ourList.modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (rem == 0) {
throw new NoSuchElementException();
}
remaining = rem - 1;
return (E) ourList.array[removalIndex = ourList.size - rem];
}
public void remove() {
Object[] a = array;
int removalIdx = removalIndex;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (removalIdx < 0) {
throw new IllegalStateException();
}
System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
a[--size] = null; // Prevent memory leak
removalIndex = -1;
expectedModCount = ++modCount;
}
}我們看到這個(gè)類實(shí)現(xiàn)了Iterator接口,接口的定義如下:
public interface Iterator {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}基本的結(jié)構(gòu)也分析完了,接下來對(duì)號(hào)入座,看一看具體是如何實(shí)現(xiàn)工廠方法模式的。
Iterator————>Product ArrayListIteratorr————>ConcreteProduct
Iterable/List————>Factory ArrayList————>ConcreteFactory
工廠方法使一個(gè)類的實(shí)例化延遲到子類,對(duì)應(yīng)著將迭代器Iterator的創(chuàng)建從List延遲到了ArrayList。這就是工廠方法模式。
重構(gòu)
暫無
抽象工廠模式
定義
為創(chuàng)建一組相關(guān)或者是相互依賴的對(duì)象提供一個(gè)接口,而不需要制定他們的具體類
抽象工廠模式是指當(dāng)有多個(gè)抽象角色時(shí),使用的一種工廠模式。抽象工廠模式可以向客戶端提供一個(gè)接口,使客戶端在不必指定產(chǎn)品的具體情況下,創(chuàng)建多個(gè)產(chǎn)品族中的產(chǎn)品對(duì)象。
示例
public abstract class AbstractProductA{
public abstract void method();
}
public abstract class AbstractProdectB{
public abstract void method();
}
public class ConcreteProductA1 extends AbstractProductA{
public void method(){
System.out.println("具體產(chǎn)品A1的方法!");
}
}
public class ConcreteProductA2 extends AbstractProductA{
public void method(){
System.out.println("具體產(chǎn)品A2的方法!");
}
}
public class ConcreteProductB1 extends AbstractProductB{
public void method(){
System.out.println("具體產(chǎn)品B1的方法!");
}
}
public class ConcreteProductB2 extends AbstractProductB{
public void method(){
System.out.println("具體產(chǎn)品B2的方法!");
}
}
public abstract class AbstractFactory{
public abstract AbstractProductA createProductA();
public abstract AbstractProductB createProductB();
}
public class ConcreteFactory1 extends AbstractFactory{
public AbstractProductA createProductA(){
return new ConcreteProductA1();
}
public AbstractProductB createProductB(){
return new ConcreteProductB1();
}
}
public class ConcreteFactory2 extends AbstractFactory{
public AbstractProductA createProductA(){
return new ConcreteProductA2();
}
public AbstractProductB createProductB(){
return new ConcreteProductB2();
}
}Android
由于該模式存在的局限性,Android中很少有用到這個(gè)模式的地方,com.android.internal.policy包下的IPolicy有使用到這個(gè)模式,它是關(guān)于Android窗口,窗口管理,布局加載,以及事件回退Handler這一系列窗口相關(guān)產(chǎn)品的抽象工廠,但是其在源碼中其實(shí)也只有一個(gè)具體的工廠實(shí)現(xiàn)。因?yàn)檫@部分結(jié)構(gòu)較為復(fù)雜,代碼量大,有興趣的同學(xué)可以自己去查看相關(guān)資料或者閱讀源碼。
與工廠方法模式對(duì)比
使用
- 不依賴于產(chǎn)品類實(shí)例如何被創(chuàng)建,組合和表達(dá)的細(xì)節(jié);
- 產(chǎn)品有多于一個(gè)的產(chǎn)品族,而系統(tǒng)只消費(fèi)其中某一族的產(chǎn)品;
- 同屬于同一個(gè)產(chǎn)品族是在一起使用的;
- 提供一個(gè)產(chǎn)品類的庫,所有產(chǎn)品以同樣的接口出現(xiàn),從而使使用者不依賴于實(shí)現(xiàn);
區(qū)別
- 抽象工廠是面向一個(gè)工廠方法的升級(jí);
- 抽象方法提供的是一個(gè)產(chǎn)品族,即多個(gè)產(chǎn)品等級(jí)結(jié)構(gòu),而工廠方法則是針對(duì)一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu);
- 抽象方法提供的產(chǎn)品是衍生自多個(gè)抽象或者接口,而工廠方法則衍生自同一個(gè)抽象或者接口;
優(yōu)點(diǎn)
- 抽象工廠模式隔離了具體類的生產(chǎn),使得客戶并不需要知道什么被創(chuàng)建。
- 當(dāng)一個(gè)產(chǎn)品族中的多個(gè)對(duì)象被設(shè)計(jì)成一起工作時(shí),它能保證客戶端始終只使用同一個(gè)產(chǎn)品族中的對(duì)象。
- 增加新的具體工廠和產(chǎn)品族很方便,無須修改已有系統(tǒng),符合“開閉原則”。
缺點(diǎn)
- 增加新的產(chǎn)品等級(jí)結(jié)構(gòu)很復(fù)雜,需要修改抽象工廠和所有的具體工廠類,對(duì)“開閉原則”的支持呈現(xiàn)傾斜性。
- (可以把示例中的AB當(dāng)做等級(jí),12當(dāng)做族群,A1B1屬于同一族群不同等級(jí),當(dāng)添加同一等級(jí)下新的產(chǎn)品時(shí)很方便,但是要添加不同等級(jí)的產(chǎn)品就會(huì)破壞“開閉原則”)
由于抽象工廠不易于拓展新的產(chǎn)品族,所以這種設(shè)計(jì)模式,在提供對(duì)外部人員訪問時(shí),很少使用,也有人說抽象工廠方法模式是一種很“惡心”的設(shè)計(jì)模式,運(yùn)用最為典范的一個(gè)是該模式最初的目的,也就是為了適應(yīng)Unit和Windows兩個(gè)操作系統(tǒng)下的視圖而構(gòu)建視圖族,視圖族有各自不同的實(shí)現(xiàn);另一個(gè)就是Java連接數(shù)據(jù)庫的操作中,對(duì)不同的數(shù)據(jù)庫的操作而形成的的對(duì)象操作族,但是當(dāng)再次更換數(shù)據(jù)時(shí),所需要造成的接口的修改也十分麻煩,所以擴(kuò)展性不好
重構(gòu)
暫無
策略模式
定義
有一系列的算法,將每個(gè)算法封裝起來(每個(gè)算法可以封裝到不同的類中),各個(gè)算法之間可以替換,策略模式讓算法獨(dú)立于使用它的客戶而獨(dú)立變化。
示例
public abstract class BaseAdvertManager {
protected abstract void doLoadAdvert();
}
public class FacebookAdvertManager extends BaseAdvertManager {
@Override
protected void doLoadAdvert() {
Log.v(TAG, "加載Facebook廣告");
}
}
public class AdmobAdvertManager extends BaseAdvertManager {
@Override
protected void doLoadAdvert() {
Log.v(TAG, "加載Admob廣告");
}
}Android
Android在屬性動(dòng)畫中使用時(shí)間插值器的時(shí)候就用到了策略模式。在使用動(dòng)畫時(shí),你可以選擇線性插值器LinearInterpolator、加速減速插值器AccelerateDecelerateInterpolator、減速插值器DecelerateInterpolator以及自定義的插值器。這些插值器都是實(shí)現(xiàn)根據(jù)時(shí)間流逝的百分比來計(jì)算出當(dāng)前屬性值改變的百分比。通過根據(jù)需要選擇不同的插值器,實(shí)現(xiàn)不同的動(dòng)畫效果。
重構(gòu)
暫無
狀態(tài)模式
定義
狀態(tài)模式中,行為是由狀態(tài)來決定的,不同狀態(tài)下有不同行為。狀態(tài)模式和策略模式的結(jié)構(gòu)幾乎是一模一樣的,主要是他們表達(dá)的目的和本質(zhì)是不同。
示例
public interface TvState{
public void nextChannerl();
public void prevChannerl();
public void turnUp();
public void turnDown();
}
public class PowerOffState implements TvState{
public void nextChannel(){}
public void prevChannel(){}
public void turnUp(){}
public void turnDown(){}
}
public class PowerOnState implements TvState{
public void nextChannel(){
System.out.println("下一頻道");
}
public void prevChannel(){
System.out.println("上一頻道");
}
public void turnUp(){
System.out.println("調(diào)高音量");
}
public void turnDown(){
System.out.println("調(diào)低音量");
}
}
public interface PowerController{
public void powerOn();
public void powerOff();
}
public class TvController implements PowerController{
TvState mTvState;
public void setTvState(TvStete tvState){
mTvState=tvState;
}
public void powerOn(){
setTvState(new PowerOnState());
System.out.println("開機(jī)啦");
}
public void powerOff(){
setTvState(new PowerOffState());
System.out.println("關(guān)機(jī)啦");
}
public void nextChannel(){
mTvState.nextChannel();
}
public void prevChannel(){
mTvState.prevChannel();
}
public void turnUp(){
mTvState.turnUp();
}
public void turnDown(){
mTvState.turnDown();
}
}
public class Client{
public static void main(String[] args){
TvController tvController=new TvController();
tvController.powerOn();
tvController.nextChannel();
tvController.turnUp();
tvController.powerOff();
//調(diào)高音量,此時(shí)不會(huì)生效
tvController.turnUp();
}
}Android
Android源碼中很多地方都有用到狀態(tài)模式,舉一個(gè)例子,就是Android的WIFI管理模塊。當(dāng)WIFI開啟時(shí),自動(dòng)掃描周圍的接入點(diǎn),然后以列表的形式展示;當(dāng)wifi關(guān)閉時(shí)則清空。這里wifi管理模塊就是根據(jù)不同的狀態(tài)執(zhí)行不同的行為。
與策略模式的區(qū)別
狀態(tài)模式的行為是平行的、不可替換的,策略模式是屬于對(duì)象的行為模式,其行為是彼此獨(dú)立可相互替換的。
重構(gòu)
項(xiàng)目中有需要功能如瘦臉等存在開關(guān),現(xiàn)在是通過配置文件進(jìn)行判斷,可以通過狀態(tài)模式進(jìn)行重構(gòu),進(jìn)而在具體處理圖片時(shí)可以利用多態(tài)的特性直接使用對(duì)象進(jìn)行處理
責(zé)任鏈模式
定義
使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接受者直接的耦合關(guān)系,將這些對(duì)象連成一條鏈,并沿這條鏈傳遞該請(qǐng)求,直到有對(duì)象處理它為止。
示例
/** * 抽象處理者 */
public abstract class Handler {
/** * 持有后繼的責(zé)任對(duì)象 */
protected Handler successor;
/** * 示意處理請(qǐng)求的方法,雖然這個(gè)示意方法是沒有傳入?yún)?shù)的 * 但實(shí)際是可以傳入?yún)?shù)的,根據(jù)具體需要來選擇是否傳遞參數(shù) */
public abstract void handleRequest();
/** * 取值方法 */
public Handler getSuccessor() {
return successor;
}
/** * 賦值方法,設(shè)置后繼的責(zé)任對(duì)象 */
public void setSuccessor(Handler successor) {
this.successor = successor;
}
}
/** * 具體處理者 */
public class ConcreteHandler extends Handler {
/** * 處理方法,調(diào)用此方法處理請(qǐng)求 */
@Override public void handleRequest() {
/** * 判斷是否有后繼的責(zé)任對(duì)象 * 如果有,就轉(zhuǎn)發(fā)請(qǐng)求給后繼的責(zé)任對(duì)象 * 如果沒有,則處理請(qǐng)求 */
if(getSuccessor() != null)
{
System.out.println("放過請(qǐng)求");
getSuccessor().handleRequest();
}else
{
System.out.println("處理請(qǐng)求");
}
}
}
/** * 發(fā)起請(qǐng)求的客戶類 */
public class Client {
public static void main(String[] args) {
//組裝責(zé)任鏈
Handler handler1 = new ConcreteHandler();
Handler handler2 = new ConcreteHandler();
handler1.setSuccessor(handler2);
//提交請(qǐng)求
handler1.handleRequest();
}
}Android
在Android處理點(diǎn)擊事件時(shí),父View先接收到點(diǎn)擊事件,如果父View不處理則交給子View,把責(zé)任依次往下傳遞;還有Java的異常捕獲機(jī)制也是責(zé)任鏈模式的一種體現(xiàn)
重構(gòu)
暫無
解釋器模式
定義
給定一個(gè)語言,定義它的語法,并定義一個(gè)解釋器,這個(gè)解釋器用于解析語言。
示例
如編寫各種功能模塊的配置文件,然后按照項(xiàng)目定義的配置文件編寫規(guī)則在運(yùn)行過程中將配置文件加載為配置對(duì)象,這個(gè)模式在日常項(xiàng)目中應(yīng)該或多或少都會(huì)使用到,就不貼出代碼了。
Android
這個(gè)用到的地方也不少,其一就是Android的四大組件需要在AndroidManifest.xml中定義,其實(shí)AndroidManifest.xml就定義了,等標(biāo)簽(語句)的屬性以及其子標(biāo)簽,規(guī)定了具體的使用(語法),通過PackageManagerService(解釋器)進(jìn)行解析。
重構(gòu)
暫無
命令模式
定義
命令模式將每個(gè)請(qǐng)求封裝成一個(gè)對(duì)象,從而讓用戶使用不同的請(qǐng)求把客戶端參數(shù)化;將請(qǐng)求進(jìn)行排隊(duì)或者記錄請(qǐng)求日志,以及支持可撤銷操作。
舉個(gè)例子來理解:當(dāng)我們點(diǎn)擊“關(guān)機(jī)”命令,系統(tǒng)會(huì)執(zhí)行一系列操作,比如暫停事件處理、保存系統(tǒng)配置、結(jié)束程序進(jìn)程、調(diào)用內(nèi)核命令關(guān)閉計(jì)算機(jī)等等,這些命令封裝從不同的對(duì)象,然后放入到隊(duì)列中一個(gè)個(gè)去執(zhí)行,還可以提供撤銷操作。
示例
public void method() {
Handler.post(new Runnable() {
@Override
public void run() {
clearCache();
statics();
finish();
}
});
}Android
在Android事件機(jī)制中,底層邏輯對(duì)事件的轉(zhuǎn)發(fā)處理。每次的按鍵事件會(huì)被封裝成NotifyKeyArgs對(duì)象,通過InputDispatcher封裝具體的事件操作。還有一個(gè)例子就是我們使用的Runnable,我們可以使用它來封裝自己想做的操作,然后交給Handler按順序處理,或者在處理前remove取消掉
重構(gòu)
現(xiàn)在的廣告模塊業(yè)務(wù)邏輯可以進(jìn)行這種模式的重構(gòu),將廣告拉取、廣告展示等請(qǐng)求都封裝成一個(gè)個(gè)的對(duì)象,放入到一個(gè)管理容器中按照一定規(guī)則進(jìn)行調(diào)用,這樣不僅可以避免在調(diào)用了展示廣告接口的時(shí)候正在拉取廣告,進(jìn)而導(dǎo)致展示次數(shù)丟失的情況,也可以在出現(xiàn)網(wǎng)絡(luò)錯(cuò)誤等異常情況時(shí)可以對(duì)一些步驟進(jìn)行取消。
觀察者模式
定義
有時(shí)被稱作發(fā)布/訂閱模式,其定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象。這個(gè)主題對(duì)象在狀態(tài)發(fā)生變化時(shí),會(huì)通知所有觀察者對(duì)象,使它們能夠自動(dòng)更新自己。
示例
Java的Observable類和Observer接口就是實(shí)現(xiàn)了觀察者模式。一個(gè)Observer對(duì)象監(jiān)視著一個(gè)Observable對(duì)象的變化,當(dāng)Observable對(duì)象發(fā)生變化時(shí),Observer得到通知,就可以進(jìn)行相應(yīng)的工作。
感興趣的可以直接去查看兩個(gè)類的源碼,這個(gè)模式比較常用,就不在這里再貼一次了。
Android
ListView的適配器有個(gè)notifyDataSetChange()函數(shù),就是通知ListView的每個(gè)Item,數(shù)據(jù)源發(fā)生了變化,各個(gè)子Item需要重新刷新一下。
重構(gòu)
比如現(xiàn)在相機(jī)選完濾鏡拍照后進(jìn)入自拍確認(rèn)頁,這時(shí)候如果用戶更換了濾鏡,那么回來的時(shí)候應(yīng)該把相機(jī)界面的濾鏡替換為最新選擇的濾鏡。目前是在相機(jī)界面的onResume函數(shù)里做這個(gè)邏輯,但是其實(shí)可以把濾鏡抽成一個(gè)完整的模塊,然后在模塊內(nèi)部自己實(shí)現(xiàn)觀察者模式,這樣一方面把濾鏡的邏輯封裝起來,與外界解耦,也符合Java多用組合的理念
EventBus
EventBus的好處很明顯,可以很方便簡單地實(shí)現(xiàn)觀察者模式,但是壞處也很明顯
- 大量的濫用,將導(dǎo)致邏輯的分散,出現(xiàn)問題后很難定位。
- 沒辦法實(shí)現(xiàn)強(qiáng)類型,在編譯的時(shí)候就發(fā)現(xiàn)問題,(Otto實(shí)現(xiàn)了這個(gè),但性能有問題)。在實(shí)現(xiàn)上通過一個(gè)很弱的協(xié)議,比如onEvent{XXX}, {XXX}表示ThreadModel,來實(shí)現(xiàn)線程的切換。
- 代碼可讀性存在問題,IDE無法識(shí)別這些協(xié)議,對(duì)IDE不友好。
所以如果出現(xiàn)了需要使用觀察者模式的情況,在各方面條件允許的情況下,建議還是在這個(gè)模塊中自己實(shí)現(xiàn)觀察者模式,如果發(fā)現(xiàn)這個(gè)功能在其他模塊也需要,那么就要考慮是不是應(yīng)該把這系列功能抽成一個(gè)更加獨(dú)立的模塊從而進(jìn)行復(fù)用,而不是貪圖方便地直接使用EventBus
備忘錄模式
定義
在不破壞封閉的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在對(duì)象之外保存這個(gè)狀態(tài),這樣,以后就可將對(duì)象恢復(fù)到原先保存的狀態(tài)中。
示例
序列化對(duì)象到本地并在必要時(shí)將對(duì)象反序列化恢復(fù)回來
public PhotoData readPhotoData(String path) {
PhotoData photoData = null;
ObjectInputStream objInput = null;
try {
objInput = new ObjectInputStream(new FileInputStream(path));
photoData = (PhotoData) objInput.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (objInput != null) {
objInput.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return photoData;
}
public void writePhotoData(PhotoData data, String path) {
ObjectOutputStream objOutput = null;
try {
objOutput = new ObjectOutputStream(new FileOutputStream(path));
objOutput.writeObject(data);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (objOutput != null) {
objOutput.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}Android
Activity的onSaveInstanceState和onRestoreInstanceState就是用到了備忘錄模式,分別用于保存和恢復(fù)。
重構(gòu)
暫無
迭代器模式
定義
提供一種方法順序訪問一個(gè)容器對(duì)象中的各個(gè)元素,而不需要暴露該對(duì)象的內(nèi)部表示。
迭代器模式是與集合共生共死的,一般來說,我們只要實(shí)現(xiàn)一個(gè)集合,就需要同時(shí)提供這個(gè)集合的迭代器,就像java中的Collection,List、Set、Map等,這些集合都有自己的迭代器。假如我們要實(shí)現(xiàn)一個(gè)這樣的新的容器,當(dāng)然也需要引入迭代器模式,給我們的容器實(shí)現(xiàn)一個(gè)迭代器。
示例
Java的Iterator就是一個(gè)抽象迭代器,通過實(shí)現(xiàn)這個(gè)接口各個(gè)集合可以提供自己定制的具體迭代器,感興趣的可以直接查看源碼
雖然我們使用集合的場景非常多,但是實(shí)際使用到迭代器的卻比較少,對(duì)于比較簡單的遍歷(像數(shù)組或者有序列表),使用迭代器方式遍歷較為繁瑣,比如ArrayList,我們更傾向于使用for循環(huán)來遍歷,但是針對(duì)hash表之類的集合來說,引入迭代器就反而簡單多了。同時(shí)我們也可以通過自定義迭代器來對(duì)有序列表提供正序遍歷或者倒序遍歷,用戶只需要得到迭代器就可以遍歷了,而不需要關(guān)心具體遍歷算法。
Android
Android源碼中,最典型的就是Cursor用到了迭代器模式,當(dāng)我們使用SQLiteDatabase的query方法時(shí),返回的就是Cursor對(duì)象,之后再通過Cursor去遍歷數(shù)據(jù)
重構(gòu)
暫無
模板方法模式
定義
定義一個(gè)操作中的算法框架,而將一些步驟延遲到子類中,使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定的步驟。
示例
public abstract class BaseAdvertManager {
public void loadAdvert(Context context, int type) {
if (NetUtils.checkNetConnection(context) != NetUtils.OK) {
return;
}
mStateArray.put(type, AdvertConstant.AD_STATE_LOADING);
doLoadAdvert(context, type);
}
protected abstract void doLoadAdvert(Context context, int type);
}廣告管理器抽象類定義了加載廣告的通用模板,但是又把模板中具體加載廣告的邏輯聲明為抽象方法為各個(gè)子類自我實(shí)現(xiàn)
Android
啟動(dòng)一個(gè)Activity過程非常復(fù)雜,有很多地方需要開發(fā)者定制,也就是說,整體算法框架是相同的,但是將一些步驟延遲到子類中,比如Activity的onCreate、onStart等等。這樣子類不用改變整體啟動(dòng)Activity過程即可重定義某些具體的操作了。
重構(gòu)
大部分代碼相同部分代碼不同的方法都可以嘗試使用模板方法重構(gòu),要么是在同一個(gè)類里面進(jìn)行方法的重構(gòu),要么通過塑造模板函數(shù)的重構(gòu)手段對(duì)子類與父類進(jìn)行重構(gòu)
項(xiàng)目中自拍確認(rèn)頁保存照片并分享與保存照片并后退目前是兩個(gè)獨(dú)立的方法,但是方法內(nèi)部大多數(shù)代碼都是一樣的,就需要用該模式進(jìn)行重構(gòu),由于代碼量大而且該重構(gòu)手段比較簡單,就不貼出代碼
訪問者模式
定義
封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中各元素的操作,它可以在不改變這個(gè)數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新的操作。
假如一個(gè)對(duì)象中存在著一些與本對(duì)象不相干(或者關(guān)系較弱)的操作,為了避免這些操作污染這個(gè)對(duì)象,則可以使用訪問者模式來把這些操作封裝到訪問者中去。
假如一組對(duì)象中,存在著相似的操作,為了避免出現(xiàn)大量重復(fù)的代碼,也可以將這些重復(fù)的操作封裝到訪問者中去。
訪問者模式的目的是封裝一些施加于某種數(shù)據(jù)結(jié)構(gòu)元素之上的操作,一旦這些操作需要修改的話,接受這個(gè)操作的數(shù)據(jù)結(jié)構(gòu)則可以保持不變。
訪問者模式是23種設(shè)計(jì)模式中最復(fù)雜最難理解的一個(gè),但他的使用率并不高,大部分情況下,我們不需要使用訪問者模式,少數(shù)特定的場景才需要。
大多數(shù)情況下,你并需要使用訪問者模式,但是當(dāng)你一旦需要使用它時(shí),那你就是真的需要它了?!狦OF《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ) 》
示例
interface Service {
public void accept(Visitor visitor);
}
class Draw implements Service {
public void accept(Visitor visitor) {
visitor.process(this);
}
}
class Fund implements Service {
public void accept(Visitor visitor) {
visitor.process(this);
}
}
class Saving implements Service {
public void accept(Visitor visitor) {
visitor.process(this);
}
}
class Visitor {
public void process(Service service) {
// 基本業(yè)務(wù)
System.out.println("基本業(yè)務(wù)");
}
public void process(Saving service) {
// 存款
System.out.println("存款");
}
public void process(Draw service) {
// 提款
System.out.println("提款");
}
public void process(Fund service) {
System.out.println("基金");
// 基金
}
}
public class Client {
public static void main(String[] args){
Service saving = new Saving();
Service fund = new Fund();
Service draw = new Draw();
Visitor visitor = new Visitor();
saving.accept(visitor);
fund.accept(visitor);
draw.accept(visitor);
}
}采用Visitor的好處如上面所示,當(dāng)需要改變其中一項(xiàng)業(yè)務(wù)的處理時(shí),不需要每個(gè)地方都進(jìn)行修改,而只需要改動(dòng)Visitor類中相應(yīng)的處理函數(shù)就可以了。也就是說它適合于業(yè)務(wù)處理時(shí)常發(fā)生變動(dòng)的情況。
當(dāng)然,Visitor也有它自身的限制。它不適合于業(yè)務(wù)數(shù)量的經(jīng)常變化,因?yàn)橐坏┬略龌騽h除一些Service時(shí),需要對(duì)Visitor進(jìn)行相應(yīng)的增刪。也就是說具體Service與Visitor是耦合的。
Android
Android中運(yùn)用訪問者模式,其實(shí)主要是在編譯期注解中,編譯期注解核心原理依賴APT(Annotation Processing Tools),著名的開源庫比如ButterKnife、Dagger、Retrofit都是基于APT。
重構(gòu)
如果是一些經(jīng)常需要變動(dòng)邏輯的業(yè)務(wù)則非常適合使用訪問者模式,如果是需要頻繁增加新的業(yè)務(wù)的,則不適合,所以Android的UI展示部分其實(shí)理論上來說是適合使用訪問者模式的,因?yàn)閁I常常一個(gè)版本一個(gè)變化,如果當(dāng)UI的變化不只是局限在XML中修修改改的話,而是已經(jīng)體現(xiàn)在了代碼中,那么可以考慮是否可以使用訪問者模式進(jìn)行修改。
目前實(shí)際項(xiàng)目中暫無這種情況,廣告模塊后續(xù)的UI渲染由于是根據(jù)不同的廣告平臺(tái)所下發(fā)的廣告對(duì)象來進(jìn)行對(duì)應(yīng)的渲染,目前每個(gè)廣告平臺(tái)渲染視圖的接口所需參數(shù)不太一樣,但是可以考慮進(jìn)行一下抽離封裝,做成一個(gè)簡單的Visitor試試看。
中介者模式
定義
中介者模式包裝了一系列對(duì)象相互作用的方式,使得這些對(duì)象不必相互明顯調(diào)用,從而使他們可以輕松耦合。當(dāng)某些對(duì)象之間的作用發(fā)生改變時(shí),不會(huì)立即影響其他的一些對(duì)象之間的作用保證這些作用可以彼此獨(dú)立的變化,中介者模式將多對(duì)多的相互作用轉(zhuǎn)為一對(duì)多的相互作用。
其實(shí),中介者對(duì)象是將系統(tǒng)從網(wǎng)狀結(jié)構(gòu)轉(zhuǎn)為以調(diào)停者為中心的星型結(jié)構(gòu)。
舉個(gè)簡單的例子,一臺(tái)電腦包括:CPU、內(nèi)存、顯卡、IO設(shè)備。其實(shí),要啟動(dòng)一臺(tái)計(jì)算機(jī),有了CPU和內(nèi)存就夠了。當(dāng)然,如果你需要連接顯示器顯示畫面,那就得加顯卡,如果你需要存儲(chǔ)數(shù)據(jù),那就要IO設(shè)備,但是這并不是最重要的,它們只是分割開來的普通零件而已,我們需要一樣?xùn)|西把這些零件整合起來,變成一個(gè)完整體,這個(gè)東西就是主板。主板就是起到中介者的作用,任何兩個(gè)模塊之間的通信都會(huì)經(jīng)過主板協(xié)調(diào)。
示例
public abstract class Person {
protected String name;
protected Mediator mediator;
Person(String name,Mediator mediator){
this.name = name;
this.mediator = mediator;
}
}
public class HouseOwner extends Person{
HouseOwner(String name, Mediator mediator) {
super(name, mediator);
}
/** * @desc 與中介者聯(lián)系 * @param message * @return void */
public void constact(String message){
mediator.constact(message, this);
}
/** * @desc 獲取信息 * @param message * @return void */
public void getMessage(String message){
System.out.println("房主:" + name +",獲得信息:" + message);
}
}
public class Tenant extends Person{
Tenant(String name, Mediator mediator) {
super(name, mediator);
}
/** * @desc 與中介者聯(lián)系 * @param message * @return void */
public void constact(String message){
mediator.constact(message, this);
}
/** * @desc 獲取信息 * @param message * @return void */
public void getMessage(String message){
System.out.println("租房者:" + name +",獲得信息:" + message);
}
}
public abstract class Mediator {
//申明一個(gè)聯(lián)絡(luò)方法
public abstract void constact(String message,Person person);
}
public class MediatorStructure extends Mediator{
//首先中介結(jié)構(gòu)必須知道所有房主和租房者的信息
private HouseOwner houseOwner;
private Tenant tenant;
public HouseOwner getHouseOwner() {
return houseOwner;
}
public void setHouseOwner(HouseOwner houseOwner) {
this.houseOwner = houseOwner;
}
public Tenant getTenant() {
return tenant;
}
public void setTenant(Tenant tenant) {
this.tenant = tenant;
}
public void constact(String message, Person person) {
if(person == houseOwner){ //如果是房主,則租房者獲得信息
tenant.getMessage(message);
}
else{ //反正則是房主獲得信息
houseOwner.getMessage(message);
}
}
}
public class Client {
public static void main(String[] args) {
//一個(gè)房主、一個(gè)租房者、一個(gè)中介機(jī)構(gòu)
MediatorStructure mediator = new MediatorStructure();
//房主和租房者只需要知道中介機(jī)構(gòu)即可
HouseOwner houseOwner = new HouseOwner("張三", mediator);
Tenant tenant = new Tenant("李四", mediator);
//中介結(jié)構(gòu)要知道房主和租房者
mediator.setHouseOwner(houseOwner);
mediator.setTenant(tenant);
tenant.constact("聽說你那里有三室的房主出租.....");
houseOwner.constact("是的!請(qǐng)問你需要租嗎?");
}
}房主:張三,獲得信息:聽說你那里有三室的房主出租…..
租房者:李四,獲得信息:是的!請(qǐng)問你需要租嗎?
Android
在Binder機(jī)制中,就用到了中介者模式。我們知道系統(tǒng)啟動(dòng)時(shí),各種系統(tǒng)服務(wù)會(huì)向ServiceManager提交注冊(cè),即ServiceManager持有各種系統(tǒng)服務(wù)的引用 ,當(dāng)我們需要獲取系統(tǒng)的Service時(shí),比如ActivityManager、WindowManager等(它們都是Binder),首先是向ServiceManager查詢指定標(biāo)示符對(duì)應(yīng)的Binder,再由ServiceManager返回Binder的引用。并且客戶端和服務(wù)端之間的通信是通過Binder驅(qū)動(dòng)來實(shí)現(xiàn),這里的ServiceManager和Binder驅(qū)動(dòng)就是中介者。
重構(gòu)
從年初開始就有在項(xiàng)目里面做MVP的重構(gòu),MVP架構(gòu)里面P層其實(shí)就是一個(gè)中介者,負(fù)責(zé)協(xié)調(diào)V和M
外觀模式/門面模式
定義
要求一個(gè)子系統(tǒng)的外部與其內(nèi)部的通信必須通過一個(gè)統(tǒng)一的對(duì)象進(jìn)行。
舉個(gè)例子,我們?cè)趩?dòng)計(jì)算機(jī)時(shí),只需按一下開關(guān)鍵,無需關(guān)系里面的磁盤、內(nèi)存、cpu、電源等等這些如何工作,我們只關(guān)心他們幫我啟動(dòng)好了就行。實(shí)際上,由于里面的線路太復(fù)雜,我們也沒辦法去具體了解內(nèi)部電路如何工作。主機(jī)提供唯一一個(gè)接口“開關(guān)鍵”給用戶就好。
示例
/** * cpu子系統(tǒng)類 */
public class CPU {
public static final Logger LOGGER = Logger.getLogger(CPU.class);
public void start() {
LOGGER.info("cpu is start...");
}
public void shutDown() {
LOGGER.info("CPU is shutDown...");
}
}
/** * Disk子系統(tǒng)類 */
public class Disk {
public static final Logger LOGGER = Logger.getLogger(Disk.class);
public void start() {
LOGGER.info("Disk is start...");
}
public void shutDown() {
LOGGER.info("Disk is shutDown...");
}
}
/** * Memory子系統(tǒng)類 */
public class Memory {
public static final Logger LOGGER = Logger.getLogger(Memory.class);
public void start() {
LOGGER.info("Memory is start...");
}
public void shutDown() {
LOGGER.info("Memory is shutDown...");
}
}
/** * 門面類(核心) */
public class Computer {
public static final Logger LOGGER = Logger.getLogger(Computer.class);
private CPU cpu;
private Memory memory;
private Disk disk;
public Computer() {
cpu = new CPU();
memory = new Memory();
disk = new Disk();
}
public void start() {
LOGGER.info("Computer start begin");
cpu.start();
disk.start();
memory.start();
LOGGER.info("Computer start end");
}
public void shutDown() {
LOGGER.info("Computer shutDown begin");
cpu.shutDown();
disk.shutDown();
memory.shutDown();
LOGGER.info("Computer shutDown end...");
}
}
/** * 客戶端類 */
public class Cilent {
public static final Logger LOGGER = Logger.getLogger(Cilent.class);
public static void main(String[] args) {
Computer computer = new Computer();
computer.start();
LOGGER.info("=================");
computer.shutDown();
}
}從上面的實(shí)例來看,有了這個(gè)Facade類,也就是Computer類,用戶就不用親自去調(diào)用子系統(tǒng)中的Disk,Memory、CPU類了,不需要知道系統(tǒng)內(nèi)部的實(shí)現(xiàn)細(xì)節(jié),甚至都不用知道系統(tǒng)內(nèi)部的構(gòu)成??蛻舳酥恍枰鶩acade交互就可以了。
Android
那么Android哪里使用到了外觀模式呢?依然回到Context,Android內(nèi)部有很多復(fù)雜的功能比如startActivty、sendBroadcast、bindService等等,這些功能內(nèi)部的實(shí)現(xiàn)非常復(fù)雜,如果你看了源碼你就能感受得到,但是我們無需關(guān)心它內(nèi)部實(shí)現(xiàn)了什么,我們只關(guān)心它幫我們啟動(dòng)Activity,幫我們發(fā)送了一條廣播,綁定了Activity等等就夠了。
重構(gòu)
暫無
代理模式
定義
給某一個(gè)對(duì)象提供一個(gè)代理,并由代理對(duì)象控制對(duì)原對(duì)象的引用。
代理模式有幾種,虛擬代理,計(jì)數(shù)代理,遠(yuǎn)程代理,動(dòng)態(tài)代理。主要分為兩類,靜態(tài)代理和動(dòng)態(tài)代理。
靜態(tài)代理
定義
靜態(tài)代理比較簡單,是由程序員編寫的代理類,并在程序運(yùn)行前就編譯好的,而不是由程序動(dòng)態(tài)產(chǎn)生代理類,這就是所謂的靜態(tài)??梢酝ㄟ^聚合和繼承兩種方式實(shí)現(xiàn),繼承方式不夠靈活,所以只介紹聚合的方式
示例
nterface Subject {
void request();
}
class RealSubject implements Subject {
public void request(){
System.out.println("RealSubject");
}
}
class Proxy implements Subject {
private Subject subject;
public Proxy(Subject subject){
this.subject = subject;
}
public void request(){
System.out.println("begin");
subject.request();
System.out.println("end");
}
}
public class ProxyTest {
public static void
文章題目:談?wù)?3種設(shè)計(jì)模式在Android項(xiàng)目中的應(yīng)用
URL標(biāo)題:http://www.dlmjj.cn/article/djjjdpj.html


咨詢
建站咨詢
