自我审视记录本_春天重新审视战略模式
自我審視記錄本
這篇博客文章希望展示另一種方法,該方法如何通過依賴注入實(shí)現(xiàn)策略模式。 作為DI框架,我選擇Spring框架
首先,讓我們看一下如何以經(jīng)典方式實(shí)施策略模式。
作為起點(diǎn),我們有一個(gè)HeroController ,應(yīng)該在HeroRepository添加英雄, HeroRepository取決于用戶選擇的存儲(chǔ)庫。
此實(shí)現(xiàn)有一些陷阱。 存儲(chǔ)庫實(shí)現(xiàn)的創(chuàng)建不受Spring Context的管理(它打破了依賴注入/控制逆向)。 一旦您想使用需要注入其他類的其他功能擴(kuò)展存儲(chǔ)庫實(shí)現(xiàn),這將很痛苦(例如,使用MeterRegistry計(jì)算此類的使用情況)。
package com.github.sparsick.springbootexample.hero.universum; import java.util.Collection; import java.util.HashSet; import java.util.Set; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; import org.springframework.stereotype.Repository; @Repository public class UniqueHeroRepository implements HeroRepository { private Set<Hero> heroes = new HashSet<>(); private Counter addCounter; public UniqueHeroRepository(MeterRegistry meterRegistry) { addCounter = meterRegistry.counter( "hero.repository.unique" ); } @Override public String getName() { return "Unique" ; } @Override public void addHero(Hero hero) { addCounter.increment(); heroes.add(hero); } @Override public Collection<Hero> allHeros() { return new HashSet<>(heroes); } } 這也打破了關(guān)注的分離。 當(dāng)我想測試控制器類時(shí),我不可能輕松地模擬存儲(chǔ)庫接口。 因此,第一個(gè)想法是將存儲(chǔ)庫實(shí)現(xiàn)的創(chuàng)建置于Spring上下文中。 庫實(shí)現(xiàn)使用@Repository批注進(jìn)行批注。 因此,Spring的組件掃描找到了它們。
接下來的問題是如何將它們注入控制器類。 在這里,Spring功能可以提供幫助。 我在控制器中定義了HeroRepository的列表。 在創(chuàng)建控制器實(shí)例的過程中必須填寫此列表。
Spring在其上下文中搜索HeroRepostiory接口的所有實(shí)現(xiàn),并將它們?nèi)糠湃肓斜碇小?該解決方案的一個(gè)缺點(diǎn)是,每個(gè)添加了英雄的人都會(huì)瀏覽HeroRepository列表以找到正確的實(shí)現(xiàn)。 可以通過在控制器構(gòu)造函數(shù)中創(chuàng)建一個(gè)以存儲(chǔ)庫名稱為鍵,對(duì)應(yīng)的實(shí)現(xiàn)為值的映射來優(yōu)化此映射。
package com.github.sparsick.springbootexample.hero.universum; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import java.util.HashMap; import java.util.List; import java.util.Map; @Controller public class HeroControllerRefactoringStep2 { private Map<String, HeroRepository> heroRepositories; public HeroControllerRefactoringStep2(List<HeroRepository> heroRepositories) { this .heroRepositories = heroRepositoryStrategies(heroRepositories); } private Map<String, HeroRepository> heroRepositoryStrategies(List<HeroRepository> heroRepositories){ Map<String, HeroRepository> heroRepositoryStrategies = new HashMap<>(); heroRepositories.forEach(heroRepository -> heroRepositoryStrategies.put(heroRepository.getName(), heroRepository)); return heroRepositoryStrategies; } @PostMapping ( "/hero/new" ) public String addNewHero( @ModelAttribute ( "newHero" ) NewHeroModel newHeroModel) { HeroRepository heroRepository = findHeroRepository(newHeroModel.getRepository()); heroRepository.addHero(newHeroModel.getHero()); return "redirect:/hero" ; } private HeroRepository findHeroRepository(String repositoryName) { HeroRepository heroRepository = heroRepositories.get(repositoryName); if (heroRepository != null ) { return heroRepository; } throw new IllegalArgumentException(String.format( "Find no repository for given repository name [%s]" , repositoryName)); } }最后一個(gè)問題是應(yīng)用程序中的其他類是否需要在運(yùn)行時(shí)選擇存儲(chǔ)庫實(shí)現(xiàn)的可能性。 我可以將私有方法復(fù)制并粘貼到每個(gè)有此需求的類中,或者將地圖的創(chuàng)建移至Spring Context并將Map注入每個(gè)類。
package com.github.sparsick.springbootexample.hero; import com.github.sparsick.springbootexample.hero.universum.HeroRepository; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import java.util.HashMap; import java.util.List; import java.util.Map; @SpringBootApplication public class HeroApplicationRefactoringStep3 { public static void main(String[] args) { SpringApplication.run(HeroApplication. class , args); } @Bean Map<String, HeroRepository> heroRepositoryStrategy(List<HeroRepository> heroRepositories){ Map<String, HeroRepository> heroRepositoryStrategy = new HashMap<>(); heroRepositories.forEach(heroRepository -> heroRepositoryStrategy.put(heroRepository.getName(), heroRepository)); return heroRepositoryStrategy; } } package com.github.sparsick.springbootexample.hero.universum; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import java.util.Map; @Controller public class HeroControllerRefactoringStep3 { private Map<String, HeroRepository> heroRepositoryStrategy; public HeroControllerRefactoringStep3(Map<String, HeroRepository> heroRepositoryStrategy) { this .heroRepositoryStrategy = heroRepositoryStrategy; } @PostMapping ( "/hero/new" ) public String addNewHero( @ModelAttribute ( "newHero" ) NewHeroModel newHeroModel) { HeroRepository heroRepository = findHeroRepository(newHeroModel.getRepository()); heroRepository.addHero(newHeroModel.getHero()); return "redirect:/hero" ; } private HeroRepository findHeroRepository(String repositoryName) { return heroRepositoryStrategy.get(repositoryName); } }這個(gè)解決方案有點(diǎn)丑陋,因?yàn)槭褂貌呗阅J讲⒉幻黠@。 因此,下一個(gè)重構(gòu)步驟是將英雄存儲(chǔ)庫地圖移至自己的組件類。 因此,可以刪除應(yīng)用程序配置中的bean定義heroRepositoryStrategy 。
package com.github.sparsick.springbootexample.hero.universum; import org.springframework.stereotype.Component; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; @Component public class HeroRepositoryStrategy { private Map<String, HeroRepository> heroRepositoryStrategies; public HeroRepositoryStrategy(Set<HeroRepository> heroRepositories) { heroRepositoryStrategies = createStrategies(heroRepositories); } HeroRepository findHeroRepository(String repositoryName) { return heroRepositoryStrategies.get(repositoryName); } Set<String> findAllHeroRepositoryStrategyNames () { return heroRepositoryStrategies.keySet(); } Collection<HeroRepository> findAllHeroRepositories(){ return heroRepositoryStrategies.values(); } private Map<String, HeroRepository> createStrategies(Set<HeroRepository> heroRepositories){ Map<String, HeroRepository> heroRepositoryStrategies = new HashMap<>(); heroRepositories.forEach(heroRepository -> heroRepositoryStrategies.put(heroRepository.getName(), heroRepository)); return heroRepositoryStrategies; } } package com.github.sparsick.springbootexample.hero.universum; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import java.net.Inet4Address; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.Map; @Controller public class HeroController { private HeroRepositoryStrategy heroRepositoryStrategy; public HeroController(HeroRepositoryStrategy heroRepositoryStrategy) { this .heroRepositoryStrategy = heroRepositoryStrategy; } @PostMapping ( "/hero/new" ) public String addNewHero( @ModelAttribute ( "newHero" ) NewHeroModel newHeroModel) { HeroRepository heroRepository = heroRepositoryStrategy.findHeroRepository(newHeroModel.getRepository()); heroRepository.addHero(newHeroModel.getHero()); return "redirect:/hero" ; } }整個(gè)示例托管在GitHub上 。
翻譯自: https://www.javacodegeeks.com/2019/09/strategy-pattern-revisited-spring.html
自我審視記錄本
總結(jié)
以上是生活随笔為你收集整理的自我审视记录本_春天重新审视战略模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java设计模式之装饰模式_Java中的
- 下一篇: lambda层保存模型出错_保存您的la