新都網(wǎng)站開發(fā)鄭州百度網(wǎng)站優(yōu)化排名
???前言:聽說有本很牛的關(guān)于Java設(shè)計(jì)模式的書——重學(xué)Java設(shè)計(jì)模式,然后買了(*^▽^*)
開始跟著小傅哥學(xué)Java設(shè)計(jì)模式吧,本文主要記錄筆者的學(xué)習(xí)筆記和心得。
打卡!打卡!
六大設(shè)計(jì)原則
(引讀:這里的節(jié)奏是,先說一下概念定義,然后是模擬場(chǎng)景,最后是反例、正例。)
一、單一職責(zé)原則
1、定義
單一職責(zé)原則,它規(guī)定一個(gè)類應(yīng)該只有一個(gè)發(fā)生變化的原因。
為什么?
因?yàn)槿绻_發(fā)的一個(gè)功能不是一次性的,當(dāng)一個(gè)Class類負(fù)責(zé)超過兩個(gè)及以上職責(zé)時(shí),當(dāng)需求不斷迭代、實(shí)現(xiàn)類持續(xù)擴(kuò)張,就會(huì)出現(xiàn)難以維護(hù)、不好擴(kuò)展、測(cè)試難度大和上線風(fēng)險(xiǎn)高等問題。
2、模式場(chǎng)景
一個(gè)視頻網(wǎng)站用戶分類的例子:
- 訪問用戶,只能看480P的高清視頻,有廣告
- 普通會(huì)員,可以看720P的超清視頻,有廣告
- VIP會(huì)員,付費(fèi)的大哥,可以看1080P的藍(lán)光視頻,無(wú)廣告
3、違背原則方案(反例)
根據(jù)上面的需求,直接編碼,實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的基本功能:根據(jù)不同的用戶類型,判斷用戶可以觀看的視頻類型。
public class VideoUserService {public void serveGrade(String userType){if ("VIP用戶".equals(userType)){System.out.println("VIP用戶,視頻1080P藍(lán)光");} else if ("普通用戶".equals(userType)){System.out.println("普通用戶,視頻720P超清");} else if ("訪客用戶".equals(userType)){System.out.println("訪客用戶,視頻480P高清");}}
}
? ? ? ? 如上,這一個(gè)類包含著多個(gè)不同的行為,多種用戶職責(zé),如果在這樣的類上繼續(xù)擴(kuò)展功能就會(huì)顯得很臃腫。比如再加一個(gè)“超級(jí)VIP會(huì)員”,可以超前點(diǎn)播,按上面的實(shí)現(xiàn)方式,只能繼續(xù)ifelse。這樣的代碼結(jié)構(gòu)每次迭代,新需求的實(shí)現(xiàn)都可能會(huì)影響到其他邏輯。
4、單一職責(zé)原則改善代碼(正例)
? ? ? ? 視頻播放是視頻網(wǎng)站的核心功能,當(dāng)完成核心功能的開發(fā)后,就需要不斷地完善用戶權(quán)限,才能更好運(yùn)營(yíng)網(wǎng)站。其實(shí)就是不斷建設(shè)用戶權(quán)益,根據(jù)不同的用戶類型提供差異化服務(wù)。
? ? ? ? 為了滿足不斷迭代的需求,就不能向上面一樣把所有職責(zé)行為混為一談,而是應(yīng)該提供一個(gè)上層的接口類,對(duì)不同的差異化用戶給出單獨(dú)的實(shí)現(xiàn)類,拆分各自的職責(zé)。
(1)定義接口
public interface IVideoUserService {// 視頻清晰級(jí)別;480P、720P、1080Pvoid definition();// 廣告播放方式;無(wú)廣告、有廣告void advertisement();
}
? ? ? ? 定義出上層接口IVideoUserService,統(tǒng)一定義需要實(shí)現(xiàn)的功能,包括視頻清晰級(jí)別接口definition()、廣告播放方式接口advertisement()。然后三種不同類型的用戶就可以分別實(shí)現(xiàn)自己的服務(wù)類,做到職責(zé)統(tǒng)一。
(2)實(shí)現(xiàn)類
????????1)訪問用戶,只能看480P的高清視頻,有廣告
public class GuestVideoUserService implements IVideoUserService {public void definition() {System.out.println("訪客用戶,視頻480P高清");}public void advertisement() {System.out.println("訪客用戶,視頻有廣告");}
}
? ? ? ? 2)普通會(huì)員,可以看720P的超清視頻,有廣告
public class OrdinaryVideoUserService implements IVideoUserService {public void definition() {System.out.println("普通用戶,視頻720P超清");}public void advertisement() {System.out.println("普通用戶,視頻有廣告");}}
? ? ? ? 3)VIP會(huì)員,付費(fèi)的大哥,可以看1080P的藍(lán)光視頻,無(wú)廣告
public class VipVideoUserService implements IVideoUserService {public void definition() {System.out.println("VIP用戶,視頻1080P藍(lán)光");}public void advertisement() {System.out.println("VIP用戶,視頻無(wú)廣告");}}
5、易擴(kuò)展示例
? ? ? ? 假設(shè)有新的需求如下:7天試用VIP會(huì)員,可以試用看1080P的藍(lán)光視頻,但是有廣告。
// 7天試用VIP用戶
public class TryVipVideoUserService implements IVideoUserService {public void definition() {System.out.println("7天試用VIP用戶,視頻1080P藍(lán)光");}public void advertisement() {System.out.println("7天試用VIP用戶,視頻有廣告");}}
????????在項(xiàng)目開發(fā)的過程中,盡可能保證接口的定義、類的實(shí)現(xiàn)以及方法開發(fā)保持單一職責(zé),對(duì)項(xiàng)目后期的迭代和維護(hù)是很好的。
二、開閉原則
1、定義
在面向?qū)ο缶幊填I(lǐng)域中,開閉原則規(guī)定軟件的對(duì)象、類、模塊和函數(shù)對(duì)擴(kuò)展應(yīng)該是開放的,但是對(duì)于修改是封閉的。
這就意味著應(yīng)該用抽象定義結(jié)構(gòu),用具體實(shí)現(xiàn)擴(kuò)展細(xì)節(jié),以此確保軟件系統(tǒng)開發(fā)和維護(hù)過程的可靠性。
開閉原則的核心思想可以理解為面向抽象編程。
小結(jié):對(duì)擴(kuò)展是開放的,對(duì)修改是封閉的。
2、模擬場(chǎng)景
?對(duì)于外部調(diào)用方,只要能體現(xiàn)出面向抽象編程,定義出接口并實(shí)現(xiàn)其方法,即不修改原有方法體,只通過繼承方式進(jìn)行擴(kuò)展,都可以體現(xiàn)出開閉原則。
?(1)場(chǎng)景案例
計(jì)算三種形狀的面積,長(zhǎng)方形、三角形,圓形。其中圓的π=3.14,但后續(xù)由于π的取值精度不適用于后面的場(chǎng)景,需要再擴(kuò)展,接下來模擬這個(gè)場(chǎng)景來體現(xiàn)開閉原則。
(2)定義接口
public interface ICalculationArea {/*** 計(jì)算面積,長(zhǎng)方形** @param x 長(zhǎng)* @param y 寬* @return 面積*/double rectangle(double x, double y);/*** 計(jì)算面積,三角形* @param x 邊長(zhǎng)x* @param y 邊長(zhǎng)y* @param z 邊長(zhǎng)z* @return 面積** 海倫公式:S=√[p(p-a)(p-b)(p-c)] 其中:p=(a+b+c)/2*/double triangle(double x, double y, double z);/*** 計(jì)算面積,圓形* @param r 半徑* @return 面積** 圓面積公式:S=πr2*/double circular(double r);}
?(3)實(shí)現(xiàn)類
特別地,這里的π取3.14D,這也是要擴(kuò)展精度的方法和體現(xiàn)開閉原則的地方。
public class CalculationArea implements ICalculationArea {private final static double π = 3.14D;public double rectangle(double x, double y) {return x * y;}public double triangle(double x, double y, double z) {double p = (x + y + z) / 2;return Math.sqrt(p * (p - x) * (p - y) * (p - z));}public double circular(double r) {return π * r * r;}}
3、違背原則方案
如果不考慮開閉原則,也不考慮整個(gè)工程服務(wù)的使用情況,直接改π值。
private final static double π = 3.141592653D;
4、開閉原則改善代碼
更好的做法,按照開閉原則。繼承父類,擴(kuò)展需要的方法,同保留原有的方法,新增自己需要的方法。它的主要目的是不能因?yàn)閭€(gè)例需求的變化二改變預(yù)定的實(shí)現(xiàn)類。
public class CalculationAreaExt extends CalculationArea {private final static double π = 3.141592653D;@Overridepublic double circular(double r) {return π * r * r;}}
擴(kuò)展后的方法滿足了π精度變化的需求,需要使用此方法的用戶可以直接調(diào)用。而其他的方法,也不影響繼續(xù)使用。