Soteware_programming_design_refactoringAndDesignPattern
19:44:48
1. 使用 Builder 简化 Composite 模式
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package com.srdc.tech.service.webConstructure; 2 3 4 5 import com.srdc.tech.service.seleniumAction.Execution.ExecutionType; 6 import com.srdc.tech.service.seleniumAction.Location.LocationType; 7 import java.util.ArrayList; 8 import java.util.List; 9 10 public class WebItem { 11 private String name; 12 private String value; 13 private String locationPath; 14 private ExecutionType exeType; 15 private LocationType locateType; 16 private WebItem parent; 17 private List<WebItem> children = new ArrayList<>(); 18 19 public WebItem(String name) { 20 this.name = name; 21 } 22 23 24 public String getName() { 25 return name; 26 } 27 28 public String getValue() { 29 return value; 30 } 31 32 public String getLocationPath() { 33 return locationPath; 34 } 35 36 public ExecutionType getExeType() { 37 return exeType; 38 } 39 40 public LocationType getLocateType() { 41 return locateType; 42 } 43 44 public void add(WebItem entry) { 45 children.add(entry); 46 } 47 48 public void setParent(WebItem parent) { 49 this.parent = parent; 50 } 51 52 public WebItem getParent() { 53 return this.parent; 54 } 55 56 public List<WebItem> getChildren() { 57 return children; 58 } 59 60 public void setName(String name) { 61 this.name = name; 62 } 63 64 public void setValue(String value) { 65 this.value = value; 66 } 67 68 public void setLocationPath(String locationPath) { 69 this.locationPath = locationPath; 70 } 71 72 public void setExeType(String exeType) { 73 if(exeType.equalsIgnoreCase("webDefault")){ 74 this.exeType = ExecutionType.webDefault; 75 } 76 if(exeType.equalsIgnoreCase("jsExecutor")){ 77 this.exeType = ExecutionType.JSExecutor; 78 } 79 if(exeType.equalsIgnoreCase("actions")){ 80 this.exeType = ExecutionType.actions; 81 } 82 } 83 84 public void setLocateType(String locateType) { 85 if(locateType.equalsIgnoreCase("xpath")){ 86 this.locateType = LocationType.xpath; 87 } 88 if(locateType.equalsIgnoreCase("id")){ 89 this.locateType = LocationType.id; 90 } 91 // todo: remain 92 } 93 94 public void setChildren(List<WebItem> children) { 95 this.children = children; 96 } 97 98 }
模仿 《重构与模式》 第六章节 Builder 简化 Composite 模式,但发现在获取单个 Item 时的不便,或是自己理解不够。Builder的应用有所得
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package com.srdc.tech.service.webConstructure; 2 3 public class WebBuilder { 4 private WebItem rootItem; 5 private WebItem currentItem; 6 7 public WebBuilder(String name){ 8 rootItem = new WebItem(name); 9 currentItem = rootItem; 10 } 11 12 public void addTo(WebItem parent, WebItem willBeAddedItem){ 13 currentItem = willBeAddedItem; 14 parent.add(currentItem); 15 } 16 17 public void addChild(WebItem childItem){ 18 addTo(currentItem,childItem); 19 } 20 21 public void addSibling(String currentName,WebItem siblingItem){ 22 WebItem parent = findParentItemBy(currentName); 23 addTo(parent,siblingItem); 24 } 25 26 public void addToParent(String parentName, WebItem willBeAddedItem){ 27 WebItem parent = findParentItemBy(parentName); 28 if(parent == null){ 29 throw new RuntimeException(String.format("missing parent web element: {0}", parentName)); 30 } 31 parent.add(willBeAddedItem); 32 } 33 34 public WebItem findParentItemBy(String parentName){ 35 WebItem parent = currentItem; 36 37 while(parent != null){ 38 if(parent.getName().equalsIgnoreCase(parentName)){ 39 return parent; 40 } 41 parent = parent.getParent(); 42 } 43 return null; 44 } 45 46 public WebItem buildWebConstructure(){ 47 return this.rootItem; 48 } 49 50 }
2019-12-21 19:08:53
Decorator
代码向类的核心职责提供装饰功能,动态添加新的功能。
把每个装饰功能放在单独的类中,并让这个类包装它所要装饰的对象,当需要执行特殊行为时,代码就可以在运行时使用装饰功能包装对象。
以下情况不适用 Decorator
1. 需要搬移装饰功能的类包含许多的公共方法, 则不使用装饰模式, 因为 transparent enclosure 透明地包装,必须实现它索要装饰的类的
所有公共方法(这会导致很多无用的代码)
(如果存在要执行对象类型的检查,需要调整代码避开此项检查)
2. 涉及多个 decorator 时,顺序要符合预期的流程。 可通过 Creation method 来访问 decorator 的组合
需要熟悉对象组合
Protection Proxy 用来保护对象, Decorator 用来为对象添加行为。
Decorator 与 Strategy
将装饰功能搬移到 Decorator 重构和 用 Strategy 替换条件逻辑重构彼此之间是竞争关系。
都可以去除与特殊情况或选择性行为相关联的条件逻辑,且它们都通过把这些行为从原来的类搬移到一个
或多个新类中达到这一目的。
不同的是 如何使用这些新类, Decorator 实例把自己包装在一个对象之外(或彼此包装),而一个或多个Strategy 实例则用在一个对象当中。
1. 不能共享 Decorator实例--每个实例只能包装一个对象,另一方面,可以通过使用 Singleton 或 Flyweight 模式很容易地共享 Strategy 实例。
2. Strategy 可以随意定义自己的接口,而 Decorator 必须与它所装饰的类的接口一致。
3. Decorator 可以透明地为多个不同的类添加行为,只要这些类与Decorator 共享同一接口。 另一方面,想使用Strategy 对象的类必须知道
它们的存在并了解如何使用它们。
4. 对包含很多数据或实现很多公共方法的类使用一个或多个 Strategy 是很常见的。另一方面,Decorator类会变得过重,占用内存过多,
如果用它们来装饰这种包含很多数据或实现很多公共方法的类。
要减少公共方法的数量, 删除,搬移或改变方法的可见性,或者考虑应用其他重构。
实现:
1 确定或创建包装类型 enclosure type ,接口或类, 声明了客户代码需要的被修饰类的公共方法。 这个包装类型被称为 :Decorator Component
如果已经有了包装类型,它应该是被修饰类所实现的接口或者被装饰类的超类。 包含状态信息的类并不是合适的包装类型。
因为 Decorator 会继承这些不需要的状态。 如果没有合适的包装类型, 应该统一接口重构/或提炼接口重构来创建一个包装类型。
2 找到为被修饰类添加装饰功能的条件逻辑 ( switch 或 If 语句),并应用 多态替换条件式重构去除这些逻辑。
在应用 多态替换条件式重构之前, 通常需要应用以 子类取代类型码 重构或用 State/Strategy 替换类型代码重构。
如果应用 以子类取代类型码重构,上一步就是创建一个 Creation Method 封装类型代码。
如果需要这样的Creation Method, 要确保它的返回类型是包装类型。
从超类中去除这些类型代码字段的时候,并不需要把类型代码的访问方法声明为抽象方法。
如果存在必须在装饰代码之前和/或之后执行的逻辑,在应用以子类取代类型码重构时, 可能需要使用形成 Template Method 重构。
3 步骤2 产生了被修饰类的一个或多个子类,应用 以委托取代继承把这些子类转换成委托类。
3.1 使每个委托类都实现包装类型
3.2 把委托类的委托字段的类型声明为包装类型
3.3 决定装饰代码在委托类调用委托之前还是之后执行。
如果在步骤2 中形成了 Template Method 重构, 委托类可能会需要调用 Template Method 引用的委托(例如,被修饰的类)的非公共方法,
如果存在该情况,改变这些方法的可见性并重新应用统一接口重构。
如果委托类委托了被修饰类中的返回未修饰对象实例的方法,确保委托类在把实例交给对象代码之前修饰它。
4。 每个委托类都用被修饰类的新建实例对自己的委托字段进行了赋值。确保这个赋值逻辑语句在委托类的构造函数中。
然后,应用 提取参数重构 提取赋值语句中实例化被修饰类的部分。 如果可能的话,重复应用 移除参数重构来移除构造函数中不必要的参数。
=========