前言:
最近對(duì)設(shè)計(jì)模式很是著迷,雖然心里念念不忘Rxjava操作符,但是沒(méi)有看過(guò)源碼大州,就想自己實(shí)現(xiàn)起來(lái)還是很難得,況且再下能力還不達(dá)標(biāo)垂谢,所以閑暇時(shí)間就想看下簡(jiǎn)單的厦画,比如設(shè)計(jì)模式,想著以后自己也能多get一項(xiàng)技能滥朱,至少讓代碼看起來(lái)更加美觀那樣咯
關(guān)于java的設(shè)計(jì)模式根暑,我百度到了一些,原本想全部一一講訴徙邻,后來(lái)發(fā)現(xiàn)還是有些難度排嫌,有些設(shè)計(jì)模式從來(lái)沒(méi)見(jiàn)過(guò),應(yīng)該是見(jiàn)識(shí)短淺缰犁,于是就挑了一些比較感興趣的來(lái)介紹
設(shè)計(jì)模式分3種淳地,分別是創(chuàng)建型,結(jié)構(gòu)型民鼓,行為型
1.創(chuàng)建型設(shè)計(jì)模式
1.1 工廠模式:
這個(gè)設(shè)計(jì)模式就是使用一個(gè)靜態(tài)方法返回同一個(gè)接口不同實(shí)現(xiàn)類薇芝,比如定義一個(gè)接口IModule
public interface IModule {
void action();
}
分別有3個(gè)實(shí)現(xiàn)類
public class ModuleA implements IModule
public class ModuleB implements IModule
public class ModuleC implements IModule
然后使用靜態(tài)方法可以根據(jù)不同類型返回對(duì)應(yīng)實(shí)現(xiàn)類,比如:
public class ModuleFactory {
public static IModule getModule(int type){
switch (type) {
case 0:
return new ModuleA();
case 1:
return new ModuleB();
default:
return new ModuleC();
}
}
}
1.2 抽象工廠模式:
這個(gè)設(shè)計(jì)模式相當(dāng)于提取1.1里面工程類ModuleFactory的方法作為接口丰嘉,然后創(chuàng)建該接口的指定實(shí)現(xiàn)類夯到,如下:
public interface IFactory {
IModule getModule();
}
然后創(chuàng)建該接口實(shí)現(xiàn)類工廠:
public class ModuleAFatory implements IFactory {
@Override
public IModule getModule() {
return new ModuleA();
}
}
public class ModuleBFactory implements IFactory {
@Override
public IModule getModule() {
return new ModuleB();
}
}
public class ModuleCFactory implements IFactory {
@Override
public IModule getModule() {
return new ModuleC();
}
}
上面創(chuàng)建ABC的指定生產(chǎn)工廠,然后在需要的時(shí)候使用:
IModule moduleA = new ModuleAFactory().getModule();
IModule moduleB = new ModuleBFactory().getModule();
IModule moduleC = new ModuleCFactory().getModule();
這樣做的好處就是讓指定工廠來(lái)生產(chǎn)特定商品饮亏,但是比1.1多出了接口文件和幾個(gè)實(shí)現(xiàn)的工廠類
1.3 建造者模式
這種設(shè)計(jì)模式就是為了方便構(gòu)建有很多屬性的變量耍贾,在初始化情況下有很多默認(rèn)值可以設(shè)置或者不設(shè)置,而且該對(duì)象不能直接new產(chǎn)生路幸,只能由內(nèi)部類生成荐开,用于保護(hù)對(duì)象
舉個(gè)例子:
定義一個(gè)接口:
public interface IAction {
void doSomething();
}
使用建造者模式返回一個(gè)實(shí)現(xiàn)對(duì)象:
public class SingleManager implements IAction{
private String arg1;
private String arg2;
private int avg1;
private int avg2;
private SingleManager(){}
void setArg1(String arg1) {
this.arg1 = arg1;
}
void setAvg1(int avg1) {
this.avg1 = avg1;
}
@Override
public void doSomething() {
//do other things
}
public static class Builder{
private String arg1 = "default";
private String arg2 = "default";
private int avg1 = 1;
private int avg2 = 2;
public Builder setArg1(String arg1) {
this.arg1 = arg1;
return this;
}
public Builder setArg2(String arg2) {
this.arg2 = arg2;
return this;
}
public Builder setAvg1(int avg1) {
this.avg1 = avg1;
return this;
}
public Builder setAvg2(int avg2) {
this.avg2 = avg2;
return this;
}
public IAction build(){
SingleManager singleManager = new SingleManager();
singleManager.setArg1(this.arg1);
singleManager.setAvg1(this.avg1);
return singleManager;
}
}
}
這是一個(gè)簡(jiǎn)單的類,里面有4個(gè)參數(shù)简肴,使用builder內(nèi)部類創(chuàng)建晃听,有默認(rèn)值可以被覆蓋,使用build方法來(lái)產(chǎn)生該對(duì)象,或者返回該對(duì)象實(shí)現(xiàn)的接口能扒,增加接口佣渴,提取方法,這樣做的好處就是可以很好封裝這個(gè)類初斑,讓外部只能初始化一次辛润,并且只能通過(guò)接口訪問(wèn)其方法,很好隱藏里面內(nèi)容的實(shí)現(xiàn)见秤,缺點(diǎn)也有砂竖,就是多了內(nèi)部類,然后代碼也有些重復(fù)
1.4 單例模式
這個(gè)模式我想見(jiàn)過(guò)的人太多了鹃答,只講3種同步的實(shí)現(xiàn)
第一種:靜態(tài)初始化
public class SingleTon {
public static SingleTon singleTon = new SingleTon();
}
第二種:雙重鎖
public class SingleTon {
private SingleTon() {
}
private static SingleTon instance;
public static SingleTon getInstance(){
if(instance==null){
synchronized(SingleTon.class){
if(instance==null){
instance=new SingleTon();
}
}
}
return instance;
}
}
第三種:內(nèi)部類
public class SingleTon {
static class Creator{
public static SingleTon singleTon = new SingleTon();
}
private SingleTon() {
}
public static SingleTon getInstance(){
return Creator.singleTon;
}
}
1.5 原型模式
該設(shè)計(jì)模式就是將一個(gè)類型復(fù)制乎澄,返回復(fù)制之后的對(duì)象,一般實(shí)現(xiàn)Cloneable接口表示這個(gè)對(duì)象可以被拷貝挣跋,否則調(diào)用clone會(huì)出錯(cuò)
public class MyObject implements Cloneable{
@Override
public MyObject clone() throws CloneNotSupportedException {
return new MyObject();
}
}
結(jié)構(gòu)性設(shè)計(jì)模式
2.1 適配器模式
使用適配器模式有2種情況三圆,第一種是擴(kuò)展新方法狞换,繼承原類避咆,并且實(shí)現(xiàn)新的接口,這個(gè)方法我感覺(jué)不好修噪,但是能用查库,返回類型會(huì)定死,第二種就是引用原類黄琼,修改之前的接口方法樊销,這個(gè)方法需要修改之前定義的接口,個(gè)人感覺(jué)也不是很好脏款,畢竟需要適配嘛
假設(shè)有一個(gè)接口定義如下:
public interface IAction {
void execute();
}
實(shí)現(xiàn)類:
public class ModuleAction implements IAction{
@Override
public void execute() {
//do something
}
}
然后現(xiàn)在由于功能變更围苫,需要加入新的功能。那么就可以這樣:
第一種方式:
添加新的接口
public interface IAction2 {
void doAction();
}
類繼承擴(kuò)展實(shí)現(xiàn)新接口
public class IAction2Impl extends ModuleAction implements IAction2{
@Override
public void doAction() {
}
}
第二種方式
接口擴(kuò)展:
public interface IActionSub extends IAction{
void doAction();
}
然后適配原先的類型:
public class IActionAdapter implements IActionSub{
IAction parent;
public IActionAdapter(IAction parent) {
this.parent = parent;
}
@Override
public void execute() {
this.parent.execute();
}
@Override
public void doAction() {
//other action
}
}
這樣IActionAdapter不會(huì)修改之前的類型撤师,也對(duì)其進(jìn)行擴(kuò)展了doAction方法
以上2種方法我個(gè)人偏愛(ài)第二種剂府,不過(guò)具體情況具體分析咯
2.2 裝飾模式
這種模式用于對(duì)一個(gè)類型變量進(jìn)行引用裝飾,并添加額外的操作或者修飾剃盾,主體部分調(diào)用類的相同的方法
舉個(gè)例子:
剛才上面我們看到IActionAdapter 實(shí)現(xiàn)了IActionSub接口腺占,如果我們需要調(diào)用這個(gè)接口需要相同方法并且加入一些其他操作該怎么包裝呢?
下面看這個(gè)包裝類可行不痒谴?
public class IModuleDecr implements IActionSub{
private IActionSub sub;
public IModuleDecr(IActionSub sub) {
this.sub = sub;
}
@Override
public void execute() {
sub.execute();
//add process others op
}
@Override
public void doAction() {
sub.doAction();
//add process action op
}
}
這個(gè)方法對(duì)IActionSub的實(shí)現(xiàn)類進(jìn)行引用衰伯,然后也實(shí)現(xiàn)這個(gè)接口,在接口實(shí)現(xiàn)體里面進(jìn)行引用調(diào)用积蔚,然后//add process 用于進(jìn)一步操作或者修飾這個(gè)方法意鲸,這就保證之前的動(dòng)作不被修改,而且也對(duì)之前的操作進(jìn)行了修飾,這就是裝飾模式怎顾,引用原類论矾,實(shí)現(xiàn)相同接口,調(diào)用原類方法并添加額外操作杆勇。
2.3 代理模式
關(guān)于代理模式贪壳,顧名思義,就是外部通過(guò)代理類來(lái)訪問(wèn)蚜退,而代理類實(shí)現(xiàn)細(xì)節(jié)闰靴,具體實(shí)現(xiàn)由目標(biāo)對(duì)象實(shí)現(xiàn),這樣可以增加或者擴(kuò)展目標(biāo)對(duì)象的功能
說(shuō)的有些懵钻注,直接上代碼:
public class IActionProxy implements IActionSub{
private IActionSub mActionSub;
public IActionProxy() {
mActionSub = new IActionAdapter(new ModuleAction());
}
@Override
public void execute() {
mActionSub.execute();
}
@Override
public void doAction() {
mActionSub.doAction();
}
}
承接上面接口蚂且,這是一個(gè)代理類,他對(duì)外的方法只有接口方法幅恋,但是具體實(shí)現(xiàn)卻是由IActionAdapter來(lái)實(shí)現(xiàn)的杏死,我們把IActionAdapter看成目標(biāo)對(duì)象,那么IActionProxy就是代理對(duì)象捆交,這樣就好像外部使用IActionProxy來(lái)調(diào)用接口方法淑翼,但是真正的實(shí)現(xiàn)是目標(biāo)對(duì)象IActionAdapter來(lái)實(shí)現(xiàn)的,這就是代理品追,對(duì)外部不可見(jiàn)玄括,具體實(shí)現(xiàn)由目標(biāo)對(duì)象實(shí)現(xiàn),方便擴(kuò)展于修改
到這里肉瓦,讀者或者有些奇怪遭京,適配器模式,裝飾模式泞莉,代理模式有什么區(qū)別呢哪雕,怎么看上去都是一樣的呢,筆者剛剛學(xué)習(xí)的時(shí)候也會(huì)產(chǎn)生這樣的想法鲫趁,后來(lái)仔細(xì)做了一些比較還是發(fā)現(xiàn)了一點(diǎn)點(diǎn)不同的斯嚎。
——適配器模式:繼承類并實(shí)現(xiàn)新擴(kuò)展接口或者引用類實(shí)現(xiàn)繼承擴(kuò)展的新接口,這個(gè)都是對(duì)原類引用饮寞。
——裝飾模式:也是對(duì)原類引用孝扛,但是卻實(shí)現(xiàn)原類相同接口,并在接口方法調(diào)用引用對(duì)象的方法幽崩,然后再方法內(nèi)部做一些其他操作起到裝飾作用苦始。
——代理模式:這個(gè)模式不會(huì)引用原類,其實(shí)只對(duì)外提供接口方法慌申,但是具體實(shí)現(xiàn)由目標(biāo)對(duì)象陌选,真正的實(shí)現(xiàn)類來(lái)實(shí)現(xiàn)理郑,這就相當(dāng)于封裝之類,外面不知道究竟誰(shuí)實(shí)現(xiàn)了咨油,只管使用您炉。
未完待續(xù)