【91期】面試官:Spring 用了哪些設計模式?說三種即可
閱讀本文大概需要 7 分鐘。
來自:網(wǎng)絡
1. 策略模式
public?interface?PrizeSender?{
??/**
???*?用于判斷當前實例是否支持當前獎勵的發(fā)放
???*/
??boolean?support(SendPrizeRequest?request);
??/**
???*?發(fā)放獎勵
???*/
??void?sendPrize(SendPrizeRequest?request);
}
//?積分發(fā)放
@Component
public?class?PointSender?implements?PrizeSender?{
??@Override
??public?boolean?support(SendPrizeRequest?request)?{
????return?request.getPrizeType()?==?PrizeTypeEnum.POINT;
??}
??@Override
??public?void?sendPrize(SendPrizeRequest?request)?{
????System.out.println("發(fā)放積分");
??}
}
//?虛擬幣發(fā)放
@Component
public?class?VirtualCurrencySender?implements?PrizeSender?{
??@Override
??public?boolean?support(SendPrizeRequest?request)?{
????return?PrizeTypeEnum.VIRTUAL_CURRENCY?==?request.getPrizeType();
??}
??@Override
??public?void?sendPrize(SendPrizeRequest?request)?{
????System.out.println("發(fā)放虛擬幣");
??}
}
//?現(xiàn)金發(fā)放
@Component
public?class?CashSender?implements?PrizeSender?{
??@Override
??public?boolean?support(SendPrizeRequest?request)?{
????return?PrizeTypeEnum.CASH?==?request.getPrizeType();
??}
??@Override
??public?void?sendPrize(SendPrizeRequest?request)?{
????System.out.println("發(fā)放現(xiàn)金");
??}
}
使用@Component注解對當前類進行標注,將其聲明為Spring容器所管理的一個bean; 聲明一個返回boolean值的類似于support()的方法,通過這個方法來控制當前實例是否為處理目標request的實例; 聲明一個類似于sendPrize()的方法用于處理業(yè)務邏輯,當然根據(jù)各個業(yè)務的不同聲明的方法名肯定是不同的,這里只是一個對統(tǒng)一的業(yè)務處理的抽象; 無論是support()方法還是sendPrize()方法,都需要傳一個對象進行,而不是簡簡單單的基本類型的變量,這樣做的好處是后續(xù)如果要在Request中新增字段,那么就不需要修改接口的定義和已經(jīng)實現(xiàn)的各個子類的邏輯;
2. 工廠方法模式
@Component
public?class?PrizeSenderFactory?{
??@Autowired
??private?List?prizeSenders;
??public?PrizeSender?getPrizeSender(SendPrizeRequest?request)?{
????for?(PrizeSender?prizeSender?:?prizeSenders)?{
??????if?(prizeSender.support(request))?{
????????return?prizeSender;
??????}
????}
????throw?new?UnsupportedOperationException("unsupported?request:?"?+?request);
??}
}
@Service
public?class?ApplicationService?{
??@Autowired
??private?PrizeSenderFactory?prizeSenderFactory;
??public?void?mockedClient()?{
????SendPrizeRequest?request?=?new?SendPrizeRequest();
????request.setPrizeType(PrizeTypeEnum.POINT);??//?這里的request一般是根據(jù)數(shù)據(jù)庫或外部調用來生成的
????PrizeSender?prizeSender?=?prizeSenderFactory.getPrizeSender(request);
????prizeSender.sendPrize(request);
??}
}
3. Builder模式
public?class?SendPrizeRequest?{
??private?final?PrizeTypeEnum?prizeType;
??private?final?int?amount;
??private?final?String?userId;
??public?SendPrizeRequest(PrizeTypeEnum?prizeType,?int?amount,?String?userId)?{
????this.prizeType?=?prizeType;
????this.amount?=?amount;
????this.userId?=?userId;
??}
??@Component
??@Scope("prototype")
??public?static?class?Builder?{
????@Autowired
????PrizeService?prizeService;
????private?int?prizeId;
????private?String?userId;
????public?Builder?prizeId(int?prizeId)?{
??????this.prizeId?=?prizeId;
??????return?this;
????}
????public?Builder?userId(String?userId)?{
??????this.userId?=?userId;
??????return?this;
????}
????public?SendPrizeRequest?build()?{
??????Prize?prize?=?prizeService.findById(prizeId);
??????return?new?SendPrizeRequest(prize.getPrizeType(),?prize.getAmount(),?userId);
????}
??}
??public?PrizeTypeEnum?getPrizeType()?{
????return?prizeType;
??}
??public?int?getAmount()?{
????return?amount;
??}
??public?String?getUserId()?{
????return?userId;
??}
}
在Builder類上必須使用@Scope注解來標注該實例為prototype類型,因為很明顯,我們這里的Builder實例是有狀態(tài)的,無法被多線程共享; 在Builder.build()方法中,我們可以通過傳入的參數(shù)和注入的bean來進行一定的業(yè)務處理,從而得到構建一個SendPrizeRequest所需要的參數(shù); Builder類必須使用static修飾,因為在Java中,如果內(nèi)部類不用static修飾,那么該類的實例必須依賴于外部類的一個實例,而我們這里本質上是希望通過內(nèi)部類實例來構建外部類實例,也就是說內(nèi)部類實例存在的時候,外部類實例是還不存在的,因而這里必須使用static修飾; 根據(jù)標準的Builder模式的使用方式,外部類的各個參數(shù)都必須使用final修飾,然后只需要為其聲明getter方法即可。
@Service
public?class?ApplicationService?{
??@Autowired
??private?PrizeSenderFactory?prizeSenderFactory;
??@Autowired
??private?ApplicationContext?context;
??public?void?mockedClient()?{
????SendPrizeRequest?request?=?newPrizeSendRequestBuilder()
????????.prizeId(1)
????????.userId("u4352234")
????????.build();
????PrizeSender?prizeSender?=?prizeSenderFactory.getPrizeSender(request);
????prizeSender.sendPrize(request);
??}
??public?Builder?newPrizeSendRequestBuilder()?{
????return?context.getBean(Builder.class);
??}
}
4. 小結
【90期】面試官:說一下使用 Redis 實現(xiàn)大規(guī)模的帖子瀏覽計數(shù)的思路
【89期】面試官 5 連問一個 TCP 連接可以發(fā)多少個 HTTP 請求?
【88期】面試官問:你能說說 Spring 中,接口的bean是如何注入的嗎?
微信掃描二維碼,關注我的公眾號
朕已閱?

