碼了好幾年代碼的打字機(jī)器我,對(duì)于設(shè)計(jì)模式這個(gè)詞,肯定是一點(diǎn)也不陌生,但是對(duì)于設(shè)計(jì)模式的理解,因?yàn)槿粘i_(kāi)發(fā)中,增刪改查較多,使用設(shè)計(jì)模式思想來(lái)優(yōu)化代碼的機(jī)會(huì)就很少。也不乏在翻閱源碼的時(shí)候,嘆服于別人優(yōu)秀高效的設(shè)計(jì)。所有今天抽出點(diǎn)時(shí)間,對(duì)設(shè)計(jì)模式做個(gè)歸納、記錄,以便日后讀到優(yōu)秀的源碼,可以自信的說(shuō),這**不就是那啥嗎,我也會(huì)寫(xiě)~~~
設(shè)計(jì)模式
設(shè)計(jì)模式(Design Pattern)是前輩們對(duì)代碼開(kāi)發(fā)經(jīng)驗(yàn)的總結(jié),是解決特定問(wèn)題的一系列套路。它不是語(yǔ)法規(guī)定,而是一套用來(lái)提高代碼可復(fù)用性、可維護(hù)性、可讀性、穩(wěn)健性以及安全性的解決方案
代理模式
一個(gè)類(lèi)代表另一個(gè)類(lèi)的功能,在代理模式中,我們創(chuàng)建具有現(xiàn)有對(duì)象的對(duì)象,以便向外界提供功能接口。
代理模式在我們的生活中也很常見(jiàn),例如程序員的女友想買(mǎi)一個(gè)法國(guó)產(chǎn)的某包包,她不需要親自去法國(guó)某個(gè)賣(mài)驢的專(zhuān)賣(mài)店去買(mǎi),而是可以在代購(gòu)手中購(gòu)買(mǎi),并獲得一些小禮物,折扣優(yōu)惠等等。
靜態(tài)代理
在代碼中,代理就是在使用者和服務(wù)提供者中間的服務(wù),提供一些在提供的服務(wù)前后處理一些事物的功能。
賣(mài)東西人的認(rèn)證(共同實(shí)現(xiàn)的接口)
public interface Seller {
void sell();
}
法國(guó)某經(jīng)銷(xiāo)商:
public class LvFactory implements Seller{
@Override
public void sell() {
System.out.println("LV廠家賣(mài)包包");
}
}
你女朋友朋友圈某個(gè)不知名好友:
class Purchase implements Seller{
private Seller seller;
public Purchase(Seller factory) {
this.seller = factory;
}
@Override
public void sell() {
System.out.println("坐飛機(jī)去法國(guó)");
seller.sell();
System.out.println("坐飛機(jī)回國(guó)");
}
}
你女朋友:
public static void main(String[] args) {
Seller lv = new LvFactory();
new Purchase(lv).sell();
}
你:
信用卡 boom~~~~~~~~~~~~~~~~~
坐飛機(jī)去法國(guó)
LV廠家賣(mài)包包
坐飛機(jī)回國(guó)
動(dòng)態(tài)代理
動(dòng)態(tài)代理有別于靜態(tài)代理,是根據(jù)代理的對(duì)象,動(dòng)態(tài)創(chuàng)建代理類(lèi)。這樣,就可以避免靜態(tài)代理中代理類(lèi)接口過(guò)多的問(wèn)題。動(dòng)態(tài)代理是實(shí)現(xiàn)方式,是通過(guò)反射來(lái)實(shí)現(xiàn)的,借助Java自帶的java.lang.reflect.Proxy,通過(guò)固定的規(guī)則生成。
舉個(gè)??,女朋友朋友圈這個(gè)代購(gòu),代購(gòu)包,也代購(gòu)手表,那我找他一起買(mǎi)一塊手表呢?
手表接口和天梭類(lèi):
public interface Watch {
void sellWatch();
}
public class TissotWatch implements Watch {
@Override
public void sellWatch() {
System.out.println("賣(mài)天梭手表");
}
}
使用 InvocationHandler 定義代理類(lèi):
public class PurchaseProxy implements InvocationHandler {
private Object object;
public PurchaseProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("坐飛機(jī)出國(guó)");
Object result = method.invoke(object, args);
System.out.println("坐飛機(jī)回國(guó)");
return result;
}
}
在朋友圈買(mǎi)包買(mǎi)表:
public static void main(String[] args) {
//賣(mài)包
Seller lvseller = new LvFactory();
PurchaseProxy lvproxy = new PurchaseProxy(lvseller);
((Seller) Proxy.newProxyInstance(lvseller.getClass().getClassLoader(), new Class[] { Seller.class }, lvproxy)).sell();
//賣(mài)表
Watch tissot = new TissotWatch();
PurchaseProxy tissotproxy = new PurchaseProxy(tissot);
((Watch) Proxy.newProxyInstance(tissot.getClass().getClassLoader(), new Class[] { Watch.class }, tissotproxy)).sellWatch();
}
坐飛機(jī)出國(guó)
LV廠家賣(mài)包包
坐飛機(jī)回國(guó)
坐飛機(jī)出國(guó)
賣(mài)天梭手表
坐飛機(jī)回國(guó)
動(dòng)態(tài)代理詳解
InvocationHandler
InvocationHandler 是一個(gè)接口,當(dāng)代理方法被調(diào)用時(shí),會(huì)調(diào)用起相對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)的 invoke 方法。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
三個(gè)參數(shù):
- proxy 代理對(duì)象
- method 代理對(duì)象調(diào)用的方法
- args 調(diào)用的方法中的參數(shù)
Proxy
Java自帶的java.lang.reflect.Proxy
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
- loader 類(lèi)加載器
- interfaces 代碼要用來(lái)代理的接口
- h 一個(gè) InvocationHandler 對(duì)象
適配器模式
我們?nèi)粘J褂玫倪m配器是一個(gè)接口轉(zhuǎn)換器,它可以是一個(gè)獨(dú)立的硬件接口設(shè)備,允許硬件或電子接口與其它硬件或電子接口相連,也可以是信息接口
在代碼中,我想實(shí)現(xiàn)一個(gè)接口中的部分功能,或者想用一個(gè)類(lèi)來(lái)冒充另一個(gè)類(lèi)來(lái)實(shí)現(xiàn)它的功能,就需要適配器模式了。
適配器模式使接口不兼容的那些類(lèi)可以一起工作,其別名為包裝器
類(lèi)適配器模式
在類(lèi)適配器模式中,適配器與適配者之間是繼承,適配著實(shí)現(xiàn)通用接口
舉個(gè)??,我國(guó)標(biāo)準(zhǔn)電壓是220v,手機(jī)充電器也是220v,日本標(biāo)準(zhǔn)電壓是110v,女朋友去日本玩,想給220v的手機(jī)用110v電壓充電,就需要一個(gè)適配器了。
日本插座:
public class JapanAC {
private final static int v = 110;
public void jcharge() {
System.out.printf("使用%dv電壓充電\n", v);
}
}
充電通用接口:
public interface Charger {
void charge();
}
買(mǎi)一個(gè) 110v升220變壓器:
public class Adaptee extends JapanAC implements Charger {
@Override
public void charge() {
System.out.println("使用適配器110v轉(zhuǎn)220v");
super.jcharge();
System.out.println("充電完成");
}
}
女朋友使用適配器充電:
public static void main(String[] args) {
Charger charger = new Adaptee();
charger.charge();
}
使用適配器110v轉(zhuǎn)220v
使用110v電壓充電
充電完成
對(duì)象適配器模式
把一只猴子偽裝成人:
有那么一種猴子:
public interface Monkey {
//吃香蕉
void eatBanana();
//騎獨(dú)輪車(chē)
void rideABike();
}
public class Shuang implements Monkey {
@Override
public void eatBanana() {
System.out.println("猴子吃香蕉");
}
@Override
public void rideABike() {
System.out.println("猴子獨(dú)輪車(chē)"); //猴子不懂人性,只會(huì)騎獨(dú)輪車(chē)
}
}
有那么個(gè)人:
public interface Human {
//吃香蕉
void eatBanana();
//開(kāi)車(chē)
void drive();
}
public class Da implements Human{
@Override
public void eatBanana() {
System.out.println("人吃香蕉");
}
@Override
public void drive() {
System.out.println("人開(kāi)車(chē)");
}
}
猴子偽裝成人的大型真猴修表演:
public class MonkeyMan implements Human{
private Monkey monkey;
public MonkeyMan(Monkey monkey) {
this.monkey = monkey;
}
@Override
public void eatBanana() {
monkey.eatBanana();
}
@Override
public void drive() {
monkey.rideABike();
}
}
猴子偽裝成人:
public static void main(String[] args) {
Monkey shuang = new Shuang();
Human human = new MonkeyMan(shuang); //猴子成人
human.drive();
}
猴子獨(dú)輪車(chē)
觀察者模式
當(dāng)對(duì)象間存在一對(duì)多關(guān)系時(shí),則使用觀察者模式(Observer Pattern)。比如,當(dāng)一個(gè)對(duì)象被修改時(shí),則會(huì)自動(dòng)通知依賴(lài)它的對(duì)象。觀察者模式屬于行為型模式。
又被稱(chēng)為發(fā)布-訂閱(Publish/Subscribe)模式
例如微博關(guān)注,多個(gè)用戶(hù)關(guān)注同一博主,博主更新,會(huì)通知到所有用戶(hù)。
羅老師微博:
public interface Bloger {
void add(Fan fan);
void del(Fan fan);
void notifySms(String sms);
}
public class Luo implements Bloger {
private List<Fan> fans;
{
fans = new ArrayList<>();
}
@Override
public void add(Fan fan) {
fans.add(fan);
}
@Override
public void del(Fan fan) {
fans.remove(fan);
}
@Override
public void notifySms(String sms) {
fans.forEach(fan -> fan.notifySms(sms));
}
}
粉絲:
public interface Fan {
void notifySms(String sms);
}
public class Xigua implements Fan {
private String name;
public Xigua(String name) {
this.name = name;
}
@Override
public void notifySms(String sms) {
System.out.println(name + " | " + sms);
}
}
羅老師直播買(mǎi)手機(jī) :
public static void main(String[] args) {
Fan leijun = new Xigua("雷軍");
Fan dongmingzhu = new Xigua("董明珠");
Fan renzhengfei = new Xigua("任正非");
Bloger luo = new Luo();
luo.add(leijun);
luo.add(dongmingzhu);
luo.add(renzhengfei);
luo.notifySms("買(mǎi)錘子,送錘子啦?。?!");
}
雷軍 | 買(mǎi)錘子,送錘子啦!??!
董明珠 | 買(mǎi)錘子,送錘子啦?。?!
任正非 | 買(mǎi)錘子,送錘子啦?。?!
實(shí)際生產(chǎn)過(guò)程中,觀察者模式往往用消息中間件來(lái)實(shí)現(xiàn)
收工
更多好玩好看的內(nèi)容,歡迎到我的博客交流,共同進(jìn)步????????WaterMin