日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
記錄自己理解的一些設(shè)計(jì)模式

記錄一下自己理解的一些 設(shè)計(jì)模式 ,并盡量使用表達(dá)清楚的例子進(jìn)行講解。

成都網(wǎng)站制作、成都網(wǎng)站建設(shè)介紹好的網(wǎng)站是理念、設(shè)計(jì)和技術(shù)的結(jié)合。成都創(chuàng)新互聯(lián)公司擁有的網(wǎng)站設(shè)計(jì)理念、多方位的設(shè)計(jì)風(fēng)格、經(jīng)驗(yàn)豐富的設(shè)計(jì)團(tuán)隊(duì)。提供PC端+手機(jī)端網(wǎng)站建設(shè),用營銷思維進(jìn)行網(wǎng)站設(shè)計(jì)、采用先進(jìn)技術(shù)開源代碼、注重用戶體驗(yàn)與SEO基礎(chǔ),將技術(shù)與創(chuàng)意整合到網(wǎng)站之中,以契合客戶的方式做到創(chuàng)意性的視覺化效果。

策略模式

策略模式應(yīng)該是最基礎(chǔ)的一個(gè)設(shè)計(jì)模式,它是對(duì)行為的一個(gè)抽象。jdk中的Comparator比較器就是一個(gè)使用策略設(shè)計(jì)模式的策略。

比如有一個(gè)Student學(xué)生類,有name和age兩個(gè)屬性。如果有個(gè)需求需要打印學(xué)生名單,并按照字母順序排序,可以使用Comparator接口并在內(nèi)部使用name進(jìn)行比較即可。 如果哪一天需要按照年齡進(jìn)行排序,那么只需要修改Comparator即可,也就是使用一個(gè)新的策略,其它完全不變。

工廠模式

工廠模式的意義在于對(duì)象的創(chuàng)建、管理可以使用工廠去管理,而不是創(chuàng)建者自身。最典型的工廠模式使用者就是Spring,Spring內(nèi)部的容器就是一個(gè)工廠,所有的bean都由這個(gè)容器管理,包括它們的創(chuàng)建、銷毀、注入都被這個(gè)容器管理。

工廠模式分簡(jiǎn)單工廠和抽象工廠。它們的區(qū)別在于抽象工廠抽象程度更高,把工廠也抽象成了一個(gè)接口,這樣可以再每添加一個(gè)新的對(duì)象的時(shí)候而不需要修改工廠的代碼。

比如有個(gè)Repository接口,用于存儲(chǔ)數(shù)據(jù),有DatabaseRepository,CacheRepository,F(xiàn)ileRepository分別在數(shù)據(jù)庫,緩存,文件中存儲(chǔ)數(shù)據(jù),定義如下:

 
 
 
  1. public interface Repository {  
  2. void save(Object obj);  
  3. }  
  4. class DatabaseRepository implements Repository {  
  5. @Override  
  6. public void save(Object obj) {  
  7. System.out.println("save in database");  
  8. }  
  9. }  
  10. class CacheRepository implements Repository {  
  11. @Override  
  12. public void save(Object obj) {  
  13. System.out.println("save in cache");  
  14. }  
  15. }  
  16. class FileRepository implements Repository {  
  17. @Override  
  18. public void save(Object obj) {  
  19. System.out.println("save in file");  
  20. }  

簡(jiǎn)單工廠的使用

 
 
 
  1. public class RepositoryFactory {  
  2. public Repository create(String type) {  
  3. Repository repository = null;  
  4. switch (type) {  
  5. case "db":  
  6. repository = new DatabaseRepository();  
  7. break;  
  8. case "cache":  
  9. repository = new CacheRepository();  
  10. break;  
  11. case "file":  
  12. repository = new FileRepository();  
  13. break;  
  14. }  
  15. return repository;  
  16. }  
  17. public static void main(String[] args) {  
  18. RepositoryFactory factory = new RepositoryFactory();  
  19. factory.create("db").save(new Object());  
  20. factory.create("cache").save(new Object());  
  21. factory.create("file").save(new Object());  
  22. }  

簡(jiǎn)單工廠的弊端在于每添加一個(gè)新的Repository,都必須修改RepositoryFactory中的代碼

抽象工廠的使用

 
 
 
  1. public interface RepositoryFactoryProvider {  
  2. Repository create();
  3. }  
  4. class DatabaseRepositoryFactory implements RepositoryFactoryProvider {  
  5. @Override  
  6. public Repository create() {  
  7. return new DatabaseRepository();  
  8. }  
  9. }  
  10. class CacheRepositoryFactory implements RepositoryFactoryProvider {  
  11. @Override  
  12. public Repository create() {  
  13. return new CacheRepository();  
  14. }  
  15. }  
  16. class FileRepositoryFactory implements RepositoryFactoryProvider {  
  17. @Override  
  18. public Repository create() {  
  19. return new FileRepository();  
  20. }  

抽象工廠的測(cè)試:

 
 
 
  1. RepositoryFactoryProvider dbProvider = new DatabaseRepositoryFactory(); 
  2. dbProvider.create().save(new Object()); 
  3. RepositoryFactoryProvider cacheProvider = new CacheRepositoryFactory(); 
  4. cacheProvider.create().save(new Object()); 
  5. RepositoryFactoryProvider fileProvider = new FileRepositoryFactory(); 
  6. fileProvider.create().save(new Object()); 

抽象工廠把工廠也進(jìn)行了抽象話,所以添加一個(gè)新的Repository的話,只需要新增一個(gè)RepositoryFactory即可,原有代碼不需要修改。

裝飾者模式

裝飾者模式的作用就在于它可以在不改變?cè)蓄惖幕A(chǔ)上動(dòng)態(tài)地給類添加新的功能。之前寫過一篇 通過源碼分析MyBatis的緩存 文章,mybatis中的query就是使用了裝飾者設(shè)計(jì)模式。

用一段簡(jiǎn)單的代碼來模擬一下mybatis中query的實(shí)現(xiàn)原理:

 
 
 
  1. @Data  
  2. @AllArgsConstructor  
  3. @ToString  
  4. class Result { // 查詢結(jié)果類,相當(dāng)于一個(gè)domain  
  5. private Object obj; 
  6.  private String sql;  
  7. }  
  8. public interface Query { // 查詢接口,有簡(jiǎn)單查詢和緩存查詢  
  9. Result query(String sql);  
  10. }  
  11. public class SimpleQuery implements Query { // 簡(jiǎn)單查詢,相當(dāng)于直接查詢數(shù)據(jù)庫,這里直接返回Result,相當(dāng)于是數(shù)據(jù)庫查詢的結(jié)果  
  12. @Override  
  13. public Result query(String sql) {  
  14. return new Result(new Object(), sql);  
  15. }  
  16. }  
  17. public class CacheQuery implements Query { // 緩存查詢,如果查詢相同的sql,不直接查詢數(shù)據(jù)庫,而是返回map中存在的Result  
  18. private Query query;  
  19. private Map cache = new HashMap<>();  
  20. public CacheQuery(Query query) {  
  21. this.query = query;  
  22. }  
  23. @Override  
  24. public Result query(String sql) {  
  25. if(cache.containsKey(sql)) {  
  26. return cache.get(sql);  
  27. }  
  28. Result result = query.query(sql);  
  29. cache.put(sql, result);  
  30. return result;  
  31. }  

測(cè)試:

 
 
 
  1. Query simpleQuery = new SimpleQuery();  
  2. System.out.println(simpleQuery.query("select * from t_student") == simpleQuery.query("select * from t_student")); // false  
  3. Query cacheQuery = new CacheQuery(simpleQuery);  
  4. System.out.println(cacheQuery.query("select * from t_student") == cacheQuery.query("select * from t_student")); // true 

這里CacheQuery就是一個(gè)裝飾類,SimpleQuery是一個(gè)被裝飾者。我們通過裝飾者設(shè)計(jì)模式動(dòng)態(tài)地給SimpleQuery添加了緩存功能,而不需要修改SimpleQuery的代碼。

當(dāng)然,裝飾者模式也有缺點(diǎn),就是會(huì)存在太多的類。

如果我們需要添加一個(gè)過濾的查詢(sql中有敏感字的就直接返回null,而不查詢數(shù)據(jù)庫),只需要可以添加一個(gè)FilterQuery裝飾者即可:

 
 
 
  1. public class FilterQuery implements Query {  
  2. private Query query;  
  3. private List words = new ArrayList<>();  
  4. public FilterQuery(Query query) {  
  5. this.query = query;  
  6. words.add("fuck");  
  7. words.add("sex");  
  8. }  
  9. @Override  
  10. public Result query(String sql) {
  11. for(String word : words) {  
  12. if(sql.contains(word)) return null;  
  13. }  
  14. return query.query(sql);  
  15. }  
  16. }  
  17. Query filterQuery = new FilterQuery(simpleQuery);  
  18. System.out.println(filterQuery.query("select * from t_student where name = 'fuck'")); // null  
  19. System.out.println(filterQuery.query("select * from t_student where name = 'format'")); // Result(obj=java.lang.Object@1b4fb997, sql=select * from t_student where name = 'format') 

代理模式

代理模式的作用是使用一個(gè)代理類來代替原先類進(jìn)行操作。比較常見的就是aop中就是使用代理模式完成事務(wù)的處理。

代理模式分靜態(tài)代理和動(dòng)態(tài)代理,靜態(tài)代理的原理就是對(duì)目標(biāo)對(duì)象進(jìn)行封裝,***調(diào)用目標(biāo)對(duì)象的方法即可。

動(dòng)態(tài)代理跟靜態(tài)代理的區(qū)別就是動(dòng)態(tài)代理中的代理類是程序運(yùn)行的時(shí)候生成的。Spring中對(duì)于接口的代理使用jdk內(nèi)置的Proxy和InvocationHandler實(shí)現(xiàn),對(duì)于類的代理使用cglib完成。

以1個(gè)UserService為例,使用jdk自帶的代理模式完成計(jì)算方法調(diào)用時(shí)間的需求:

 
 
 
  1. // UserService接口  
  2. public interface IUserService {  
  3. void printAll();  
  4. }  
  5. // UserService實(shí)現(xiàn)類  
  6. class UserService implements IUserService {  
  7. @Override  
  8. public void printAll() {  
  9. System.out.println("print all users");  
  10. }  
  11. }  
  12. // InvocationHandler策略,這里打印了方法調(diào)用前后的時(shí)間  
  13. @AllArgsConstructor  
  14. class UserInvocationHandler implements InvocationHandler {  
  15. private IUserService userService;  
  16. @Override  
  17. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  18. System.out.println("start : " + System.currentTimeMillis());  
  19. Object result = method.invoke(userService, args);  
  20. System.out.println("end : " + System.currentTimeMillis());  
  21. return result;  
  22. }  

測(cè)試:

 
 
 
  1. IUserService userService = new UserService();  
  2. UserInvocationHandler uih = new UserInvocationHandler(userService);  
  3. IUserService proxy = (IUserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), new Class[] {IUserService.class}, uih); 
  4. proxy.printAll(); // 打印出start : 1489665566456 print all users end : 1489665566457 

組合模式

組合模式經(jīng)常跟策略模式配合使用,用來組合所有的策略,并遍歷這些策略找出滿足條件的策略。之前寫過一篇 SpringMVC關(guān)于json、xml自動(dòng)轉(zhuǎn)換的原理研究 文章,里面springmvc把返回的返回值映射給用戶的response做了一層抽象,封裝到了HandlerMethodReturnValueHandler策略接口中。

在HandlerMethodReturnValueHandlerComposite類中,使用存在的HandlerMethodReturnValueHandler對(duì)返回值進(jìn)行處理,在HandlerMethodReturnValueHandlerComposite內(nèi)部的代碼如下:

 
 
 
  1. // 策略集合  
  2. private final List returnValueHandlers = new ArrayList();  
  3. @Override  
  4. public void handleReturnValue(Object returnValue, MethodParameter returnType,  
  5. ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { 
  6.  // 調(diào)用selectHandler方法  
  7. HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);  
  8. if (handler == null) {  
  9. throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());  
  10. }  
  11. handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); // 使用找到的handler進(jìn)行處理  
  12. }  
  13. private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {  
  14. boolean isAsyncValue = isAsyncReturnValue(value, returnType);  
  15. // 遍歷存在的HandlerMethodReturnValueHandler  
  16. for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {  
  17. if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {  
  18. continue;  
  19. }  
  20. if (handler.supportsReturnType(returnType)) { // 找到匹配的handler  
  21. return handler;  
  22. }  
  23. }  
  24. return null;  

模板模式

跟策略模式類似,模板模式會(huì)先定義好實(shí)現(xiàn)的邏輯步驟,但是具體的實(shí)現(xiàn)方式由子類完成,跟策略模式的區(qū)別就是模板模式是有邏輯步驟的。比如要給院系里的學(xué)生排序,并取出***的學(xué)生。這里就有2個(gè)步驟,分別是排序和取出***名學(xué)生。

一段偽代碼:

 
 
 
  1. public abstract class AbstractStudentGetter {  
  2. public final Student getStudent(List students) {  
  3. sort(students); // ***步  
  4. if(!CollectionUtils.isEmpty(students)) {  
  5. return students.get(0); // 第二步  
  6. }  
  7. return null;  
  8. }  
  9. abstract public void sort(List students);  
  10. }  
  11. class AgeStudentGetter extends AbstractStudentGetter { // 取出年紀(jì)***的學(xué)生  
  12. @Override  
  13. public void sort(List students) {  
  14. students.sort(new Comparator() { 
  15.  @Override  
  16. public int compare(Student s1, Student s2) {  
  17. return s2.getAge() - s1.getAge();  
  18. }  
  19. });  
  20. }  
  21. class NameStudentGetter extends AbstractStudentGetter { // 按照名字字母排序取出***個(gè)學(xué)生  
  22. @Override  
  23. public void sort(List students) {  
  24. students.sort(new Comparator() {  
  25. @Override  
  26. public int compare(Student s1, Student s2) {  
  27. return s2.getName().compareTo(s1.getName());  
  28. }  
  29. });  
  30. }  

測(cè)試:

 
 
 
  1. MetricsObserable metricsObserable = new MetricsObserable(); 
  2. metricsObserable.addObserver(new AdminA()); 
  3. metricsObserable.addObserver(new AdminB()); 
  4. metricsObserable.updateCounter("request-count", 100l); 

觀察者設(shè)計(jì)模式

觀察者設(shè)計(jì)模式主要的使用場(chǎng)景在于一個(gè)對(duì)象變化之后,依賴該對(duì)象的對(duì)象會(huì)收到通知。典型的例子就是rss的訂閱,當(dāng)訂閱了博客的rss之后,當(dāng)博客更新之后,訂閱者就會(huì)收到新的訂閱信息。

jdk內(nèi)置提供了Observable和Observer,用來實(shí)現(xiàn)觀察者模式:

 
 
 
  1. // 定義一個(gè)Observable  
  2. public class MetricsObserable extends Observable {  
  3. private Map counterMap = new HashMap<>();  
  4. public void updateCounter(String key, Long value) {  
  5. counterMap.put(key, value);  
  6. setChanged();  
  7. notifyObservers(counterMap);  
  8. }  
  9. }  
  10. // Observer  
  11. public class AdminA implements Observer {  
  12. @Override  
  13. public void update(Observable o, Object arg) {  
  14. System.out.println("adminA: " + arg);  
  15. }  
  16. }  
  17. public class AdminB implements Observer {  
  18. @Override  
  19. public void update(Observable o, Object arg) {  
  20. System.out.println("adminB: " + arg);  
  21. }  

測(cè)試:

 
 
 
  1. MetricsObserable metricsObserable = new MetricsObserable();  
  2. metricsObserable.addObserver(new AdminA());  
  3. metricsObserable.addObserver(new AdminB());  
  4. metricsObserable.updateCounter("request-count", 100l); 

打印出:

 
 
 
  1. adminB: {request-count=100}  
  2. adminA: {request-count=100} 

享元模式

線程池中會(huì)構(gòu)造幾個(gè)核心線程用于處理,這些線程會(huì)去取阻塞隊(duì)列里的任務(wù)然后進(jìn)行執(zhí)行。這些線程就是會(huì)被共享、且被重復(fù)使用的。因?yàn)榫€程的創(chuàng)建、銷毀、調(diào)度都是需要消耗資源的,沒有必要每次創(chuàng)建新的線程,而是共用一些線程。這就是享元模式的使用。類似的還有jdbc連接池,對(duì)象池等。

之前有一次面試被問到:

 
 
 
  1. Integer.valueOf("1") == Integer.valueOf("1") // true還是false 

當(dāng)時(shí)回答的是false,后來翻了下Integer的源碼發(fā)現(xiàn)Integer里面有個(gè)內(nèi)部類IntegerCache,用于緩存一些共用的Integer。這個(gè)緩存的范圍可以在jvm啟動(dòng)的時(shí)候進(jìn)行設(shè)置。

其實(shí)后來想想也應(yīng)該這么做,我們沒有必要每次使用對(duì)象的時(shí)候都返回新的對(duì)象,可以共享這些對(duì)象,因?yàn)樾聦?duì)象的創(chuàng)建都是需要消耗內(nèi)存的。

適配器模式

適配器模式比較好理解。像生活中插線口的插頭有2個(gè)口的,也有3個(gè)口的。如果電腦的電源插口只有3個(gè)口的,但是我們需要一個(gè)2個(gè)口的插口的話,這個(gè)時(shí)候就需要使用插座來外接這個(gè)3個(gè)口的插頭,插座上有2個(gè)口的插頭。

這個(gè)例子跟我們編程一樣,當(dāng)用戶系統(tǒng)的接口跟我們系統(tǒng)內(nèi)部的接口不一致時(shí),我們可以使用適配器來完成接口的轉(zhuǎn)換。

使用繼承的方式實(shí)現(xiàn)類的適配:

 
 
 
  1. public class Source {  
  2. public void method() {  
  3. System.out.println("source method");  
  4. }  
  5. }  
  6. interface Targetable {  
  7. void method();  
  8. void newMethod();  
  9. }  
  10. class Adapter extends Source implements Targetable {  
  11. @Override  
  12. public void newMethod() {  
  13. System.out.println("new method");  
  14. }  

測(cè)試:

 
 
 
  1. Targetable targetable = new Adapter();  
  2. targetable.method(); // source method  
  3. targetable.newMethod(); // new method 

上述方式是用接口和繼承的方式實(shí)現(xiàn)適配器模式。當(dāng)然我們也可以使用組合的方式實(shí)現(xiàn)(把Source當(dāng)成屬性放到Adapter中)。

單例模式

單例模式比較好理解,Spring就是典型的例子。被Spring中的容器管理的對(duì)象都有對(duì)應(yīng)的scope,配置成singleton說明這個(gè)對(duì)象就是單例,也就是在Spring容器的生命周期中,這個(gè)類只有1個(gè)實(shí)例。

java中單例模式的寫法也有好多種。比如懶漢式、餓漢式、內(nèi)部類方式、枚舉方式等。

需要注意的如果使用dcl的話需要初始化過程,這篇 Java內(nèi)存模型之從JMM角度分析DCL 文章中說明了dcl的正確用法。

Effectice java中推薦的單例方式寫法是使用枚舉類型的方式。

外觀模式

外觀模式用來包裝一組接口用于方便使用。 比如系統(tǒng)中分10個(gè)模塊,有個(gè)功能需要組合使用所有的模塊,這個(gè)時(shí)候就需要一個(gè)包裝類包裝這10個(gè)接口,然后進(jìn)行業(yè)務(wù)邏輯的調(diào)用。


本文名稱:記錄自己理解的一些設(shè)計(jì)模式
分享URL:http://www.5511xx.com/article/dhhidjj.html