从问题角度来思考设计模式(3)
来源:互联网 发布:淘宝客服怎么做兼职 编辑:程序博客网 时间:2024/05/01 06:49
目录
- 生成编
- 结构编
- 行为编
让数据和处理逻辑分离
- 改造前
public class FooAmusementPark { private FooZoo zoo; private FooAquarium aquarium; public void enjoy(FooFamily family) { zoo.enjoy(); } public void enjoy(FooCouple couple) { aquarium.enjoy(); }}
当Family
,Couple
以外类型的用户增加时,FooAmusementPark类则必须扩充- 改造后Visitor
public class FooAmusementPark { private FooZoo zoo; private FooAquarium aquarium; public void accept(FooVisitor visitor) { visitor.visit(this); }}public class FooFamily extends FooVisitor { @Override public void visit(FooAmusementPark park) { park.getZoo().enjoy(); }}public class FooCouple extends FooVisitor { @Override public void visit(FooAmusementPark park) { park.getAquarium().enjoy(); }}
改造后,Family
,Couple
以外类型的用户增加时,AmusementPark
不需要更改,通过其中的visit
方法就能满足需求。当数据结构不经常变化的,是使用Visitor
模式的考虑点。需求多变时,如何分离处理逻辑
- 改造前
public class FooController { private FooLatLngToPlaceAPI api; public String getFormattedAddress(double latitude, double longitude) { FooPlace place = api.getPlace(latitude, longitude); return place.getPostalCode() + System.lineSeparator() + place.getProvince() + " " + place.getCity(); }}
假设返回的数据邮编 换行 省 市
格式。下一次迭代可能又换成邮编 省-市
或者其它。当多个地方返回地址数据都希望保持同一的格式时,一个个去拼装字符串就显得有些繁琐了。- 改造后Strategy
public class FooController { private FooLatLngToPlaceAPI api; private FooAddressFormatter formatter = new FooAddressFormatter(); public String getFormattedAddress(double latitude, double longitude) { FooPlace place = api.getPlace(latitude, longitude); return formatter.format(place); }}public class FooAddressFormatter { public String format(FooPlace place) { return place.getPostalCode() + System.lineSeparator() + place.getProvince() + " " + place.getCity(); }}
将拼装返回数据的逻辑单独封装成一个类。当需求变化时,也只需要改动这个类的逻辑即可,而又能保持全局格式统一。当不想创建一个新类时,也可以这样子写public class FooController { private FooLatLngToPlaceAPI api; private static final Function<FooPlace, String> FORMAT_ADDRESS = place -> place.getPostalCode() + System.lineSeparator() + place.getPrefecture() + " " + place.getCity(); public String getFormattedAddress(double latitude, double longitude) { FooPlace place = api.getPlace(latitude, longitude); return FORMAT_ADDRESS.apply(place); }}
根据条件区分近似的处理逻辑
- 改造前
public String getFormattedText(String text, FormatType type) { switch (type) { case BOLD: return "**" + text + "**"; case ITALIC: return "*" + text + "*"; default: return text; }}
当type
值变多时,switch里的条件判断及代码块就变得越来越多了,不利代码维护。- 改造后Strategy + Factory
public class FooFormatterFactory { private FooFormatterFactory() {} public static FooFormatter create(FormatType type) { switch (type) { case BOLD: return new FooBoldFormatter(); case ITALIC: return new FooItalicFormatter(); default: return new FooFormatter() { @Override public String format(String text) { return text; } } } }}public class FooBoldFormatter extends FooFormatter { @Override public String format(String text) { return "**" + text + "**"; }}public class FooItalicFormatter extends FooFormatter { @Override public String format(String text) { return "*" + text + "*"; }}
public String getFormattedText(String text, FormatType type) { return FooFormatterFactory.create(type).format(text);}
改造后,当type
值变多时,getFormattedText
方法内容则不受影响。通过Strategy
和Factory
模式结合使用的例子挺多的。当不想创建新类的时,可以参考下面代码,用函数式接口实现public class FooFormatterFactory { private FooFormatterFactory() {} public static UnaryOperator<String> create(FormatType type) { switch (type) { case BOLD: return text -> "**" + text + "**"; case ITALIC: return text -> "*" + text + "*"; default: return text -> text; } }}
public String getFormattedText(String text, FormatType type) { return FooFormatterFactory.create(type).apply(text);}
如何利用上一次处理的结果
- 改造前
public class FooController { private int nextId; public FooResponse get(FooRequest request) { FooResponse response = getResponse(request); nextId = response.getNextId(); return response; } public FooResponse getNext() { FooRequest request = new FooRequest(nextId); return get(request); } private FooResponse getResponse(FooRequest request) { // 处理 return // 结果 }}
在getNext()
方法中把包含上一次的结果的nextId做为参数生成request
实例。当request
生成时所需要的参数的数量或类型改变时,FooController
中所有的值,逻辑等都需要变更。- 改造后Memento
public class FooMemento { private int nextId; public void update(FooResponse response) { this.nextId = response.getNextId(); } public FooRequest createNextRequest() { return new FooRequest(nextId); }}
public class FooController { private FooMemento memento = new FooMemento(); public FooResponse get(FooRequest request) { FooResponse response = getResponse(request); memento.update(response); return response; } public FooResponse getNext() { return get(memento.createNextRequest()); } private FooResponse getResponse(FooRequest request) { // 处理 return // 结果 }}
通过Memento
模式来记忆上次数据。当新request
生成时所需要的参数变化时,只需要在FooMemento
中做修改。Memento
还经常用到单机游戏里,如小时候玩的存档型游戏,存档就是记录某进度下的角色们的各种状态,位置,关卡等信息。当读取存档时,其实也就是读取里面的状态数据,将程序恢复到该时刻。查看原文:https://www.huuinn.com/archives/312
更多技术干货:风匀坊
关注公众号:风匀坊
阅读全文
0 0
- 从问题角度来思考设计模式(3)
- 从问题角度来思考设计模式(1)
- 从问题角度来思考设计模式(2) – 结构编
- 从面相对象来思考设计模式
- 从哲学的角度来思考程序
- 从设计模式来说如何思考问题?
- 从研究的角度来思考软件设计模式——研究方向
- 培训-从学员的角度思考问题
- 设计模式------从小说的角度来理解
- 从实例角度分析Java设计模式
- 从设计模式角度看ArcGIS Engine
- 从spark源码的角度思考scala中的模式匹配
- 从追MM谈23种设计模式 --- 很经典! 学会用设计模式思考问题
- 换角度思考问题
- 思考问题的角度
- 从易于扩展扩展的角度来设计FizzBuzzWhizz
- 从AI的角度来分析斗地主设计
- 从模式角度理解Android架构设计-Facade模式
- 洛谷-1783 海滩防御
- JavaScript之JMap
- ASCII
- Java IO流(一)
- 常用类
- 从问题角度来思考设计模式(3)
- “Hello World”在Linux系统上的运行过程
- NKOJ 3805 距离(线性筛)
- [深度学习]卷积神经网络快速入门
- 每周LeetCode算法题(六): 617. Merge Two Binary Trees
- RMI 实现的rpc 远程过程调用 Java
- Coursera自然语言处理 Week2 笔记
- 4. Median of Two Sorted Arrays
- minikube 快速搭建k8s