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