一、定義
政策模式的定義:政策模式就是将一系列算法封裝起來,并使它們之間互相替換。被封裝起來的算法具有獨立性外部不可改變其特性。--《來源于網絡》
二、解決的問題
解決代碼中充斥大量if...else造成高耦合度和複雜度,增加代碼維護成本。
三、UML結構示意圖
四、實際應用
話說小編在入職一家新公司後,接到了一個代碼維護的項目,需要面對一堆的祖傳代碼,其中有一個1000多行的類核心代碼大概像下面這個樣子:
if(condition1){
}else if(condition2){
}else if(condition3){
}else if(condition4){
}else{
}
每個分支中都有數十行甚至數百行代碼,正常情況下小編是不會主動去調整祖傳代碼的,這裡要遵從‘夠用原則’,能跑就行。但是這部分代碼以後需要我來維護,而且就在小編入職不久就修改了兩次,是以,就決定進行優化。
再說一些關于優化代碼的題外話。像小編這種情況各位朋友可能也遇到過,自己編寫代碼的時候也有過類似的情況,項目工期緊、項目初期業務簡單,是以在編碼的合理性上可能會有不妥的地方。首先,我沒有覺得這有什麼不妥,還是夠用原則。但是在業務發生變化的時候,我們就要考慮優化原來編碼中‘不妥’的地方,那麼什麼時候去優化呢?小編給出的建議是,當同一部分代碼改動超過2次以上(再一再二不再三);再者就是,從項目初期就可預見的需要大量的條件判斷,這個時候就不要偷懶了,一定要優化,否則都是給自己挖的坑。
下面開始進行代碼優化,采用政策模式解決上面if...else。為了安全起見,首先将各個判斷語句間的代碼從各個分支中剝離出來,然後進行測試,看看輸出是否有問題,剝離後的代碼如下所示:
if(condition1){
doSomething1()
}else if(condition2){
doSomething2()
}else if(condition3){
doSomething3()
}else if(condition4){
doSomething4()
}else{
doOther()
}
doSomething1()
doSomething2()
doSomething3()
doSomething4()
doOther()
代碼剝離後,就可以編寫政策代碼,并将各個方法遷移到各自的政策中。
首先,建立HandlerStrategy接口類
interface HandlerStrategy {
void doSomething();
}
編寫3個實作類,Handler1、Handler2、Handler3
class Handler1 implements HandlerStrategy{
@Override
public void doSomething() {
System.out.println("Handler1--->doSomething");
}
}
class Handler2 implements HandlerStrategy{
@Override
public void doSomething() {
System.out.println("Handler2--->doSomething");
}
}
class Handler3 implements HandlerStrategy{
@Override
public void doSomething() {
System.out.println("Handler3--->doSomething");
}
}
編寫政策工廠類
final class HandlerProvider {
private HandlerProvider() {
}
static HandlerStrategy getHandler(String type) {
if (type.equals("Handler1")) {
return new Handler1();
} else if (type.equals("Handler2")) {
return new Handler2();
} else if (type.equals("Handler3")) {
return new Handler3();
} else {
return null;
}
}
}
上面的代碼完全可以實作功能,但是沒有解決耦合的問題,隻是将耦合點換了個地方,并且每增加一種政策都需要改動工廠類,不符合開閉原則。
繼續優化,增加抽象工廠
public interface HandlerFactory {
HandlerStrategy createHandler();
}
分别為不同的handler建立各自的工廠
public class Handler1Factory implements HandlerFactory{
@Override
public HandlerStrategy createHandler() {
return new Handler1();
}
}
public class Handler2Factory implements HandlerFactory{
@Override
public HandlerStrategy createHandler() {
return new Handler3();
}
}
public class Handler3Factory implements HandlerFactory{
@Override
public HandlerStrategy createHandler() {
return new Handler3();
}
}
并将HandlerProvider修改為如下:
final class HandlerProvider {
private static Map<String,HandlerFactory> handlerFactorys = new HashMap<>(3);
static {
handlerFactorys.put("Handler1",new Handler1Factory());
handlerFactorys.put("Handler2",new Handler2Factory());
handlerFactorys.put("Handler3",new Handler3Factory());
}
private HandlerProvider() {
}
static HandlerStrategy getHandler(String type) {
return handlerFactorys.get(type).createHandler();
}
}
此時,我們可以看到已經将if...else優化掉了。但是,新增政策的時候,依然還是要改動
HandlerProvider,并且沒增加一種政策都要對應增加抽象工廠,代碼量相對較大,繼續優化。
将建立handler的抽象工廠類删除,并将建立handler的工廠方法遷移至handler中,代碼如下:
class Handler1 implements HandlerStrategy{
private Handler1(){}
static Handler1 getInstance(){
return new Handler1();
}
@Override
public void doSomething() {
System.out.println("Handler1--->doSomething");
}
}
class Handler2 implements HandlerStrategy{
private Handler2(){}
static Handler2 getInstance(){
return new Handler2();
}
@Override
public void doSomething() {
System.out.println("Handler2--->doSomething");
}
}
class Handler3 implements HandlerStrategy{
private Handler3(){}
static Handler3 getInstance(){
return new Handler3();
}
@Override
public void doSomething() {
System.out.println("Handler3--->doSomething");
}
}
建立枚舉類,EHandler,用于儲存handler類型間的關系,代碼如下:
public enum EHandler {
Handler1Type(Handler1.getInstance()),
Handler2Type(Handler2.getInstance()),
Handler3Type(Handler3.getInstance());
private HandlerStrategy handlerStrategy;
public HandlerStrategy getHandlerStrategy(){
return this.handlerStrategy;
}
EHandler(HandlerStrategy handlerStrategy){
this.handlerStrategy = handlerStrategy;
}
}
建立HandlerHelper,用于對外調用使用,整個政策的包,隻對外暴露HandlerHelper,調用者根本不需要知道包内部是如何實作的。
public final class HandlerHelper {
private HandlerHelper(){}
public static void doHandler(String type){
EHandler.valueOf(type).getHandlerStrategy().doSomething();
}
}
驗證程式:
public class Main {
public static void main(String[] args) {
HandlerHelper.doHandler("Handler1Type");
HandlerHelper.doHandler("Handler2Type");
HandlerHelper.doHandler("Handler3Type");
}
}
運作結果:
Handler1--->doSomething
Handler2--->doSomething
Handler3--->doSomething
至此,完成了if...else的優化,不足的地方是新增handler的時候,還是需要維護枚舉類。這個就要看具體的需求了,如果政策數量不是很多可以考慮采用這種方式;如果政策數量多,可以考慮采用反射。
五、複盤
今天主要和大家分享政策模式,順便分享了一下優化代碼的一些心得,并且演練了一下優化if...else的過程。今天的分享就到這裡,歡迎各位小夥伴留言,共同進步。