我的许多同事都介绍了激动人心的新技术和框架,以帮助您提高编程专业知识。 但是目前,我认为重要的是回头并涵盖一个重要的编程基础。 在我的整个编程生涯中,我所见过的最常见的反模式之一就是“字符串状态”。 在我从事的每个项目中,它都以某种形式出现。 简而言之,“字符串状态”反模式是使用Java字符串表示对象的状态。 当然,状态的字符串表示很重要。 您希望代码是可读的,想要数据库中报表的值可读,并且希望用户可读的状态表示形式呈现在界面上。 所有这些都是好东西,您应该使用状态的某种字符串表示形式,但是不要让string成为状态的整个实现。 以这个购物车的简化版本为例:
package stringstate;
public class Item {
private String name;
private int price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
package stringstate;
public interface OrderState {
public static String OPEN = "Open";
public static String CLOSED = "Closed";
}
package stringstate;
import java.util.ArrayList;
import java.util.List;
public class Order extends Item implements OrderState {
private List items = new ArrayList();
private String orderState;
public List getItems() {
return items;
}
protected void setItems(List items) {
this.items = items;
}
public String getOrderState() {
return orderState;
}
public void setOrderState(String orderState) {
this.orderState = orderState;
}
public void addItem(Item anItem){
getItems().add(anItem);
}
}
在此示例中,状态不用于任何业务逻辑。 在这种情况下,字符串状态不会有害。 但是,没有一个项目会如此简单。 即使状态仅以显示/存储开始,您最终还是会将其用于业务逻辑。 相信我-如果对象的状态足以存储,那么最终您将不得不做出决定。 因此,现在您过于简化的购物车需要防止人们在关闭时添加商品。 简单:添加新方法并修改addItem 。
public void addItem(Item anItem){
if (canModify()){
getItems().add(anItem);
} else {
throw new IllegalStateException("Cannot add items to a closed order");
}
}
public boolean canModify(){
return getOrderState().equals(OPEN);
}
到目前为止还不错。 为什么我对您要求的字符串状态这么不满意? 因为现在您要添加2个新状态“ 新建”和“已完成”,并为用户提供重新打开未完成订单的选项。 当然,一种新的方法,一个修改canModify,在setOrderState检查,我们对我们的方式。 但是,等等,现在用户想要2个完成状态: 已 发货和已取消 。 再进行一些调整,对吗? 现在,您的订单代码中充斥着与状态有关的“ if语句”:
package stringstate;
import java.util.ArrayList;
import java.util.List;
public class Order extends Item implements OrderState {
private List items = new ArrayList();
private String orderState;
public List getItems() {
return items;
}
protected void setItems(List items) {
this.items = items;
}
public String getOrderState() {
return orderState;
}
public void setOrderState(String orderState) {
if (!isFinalized()){
this.orderState = orderState;
}
}
public void addItem(Item anItem){
if (canModify()){
getItems().add(anItem);
} else {
throw new IllegalStateException("Cannot add items to a closed order");
}
}
public boolean canModify(){
return getOrderState().equals(OPEN);
}
public void reOpen(){
if (!isFinalized()){
setOrderState(OPEN);
}
}
public boolean isFinalized(){
return getOrderState().equals(SHIPPED) || getOrderState().equals(CANCELED);
}
}
糟糕,我们忘记将新状态添加到canModify() 。 现在以策略状态为例,其中所有状态逻辑都委派给比字符串更智能的对象。 第一个好处是使所有逻辑与订单有关,而不是与订单状态有关。 下一个好处是,只要您基于状态添加新决策,就可以抽象地实施该决策,以强制在所有状态下实施或提供默认实施。 订购:
package strategystate;
import java.util.ArrayList;
import java.util.List;
public class Order {
private List items = new ArrayList();
private OrderState orderState;
public List getItems() {
return items;
}
protected void setItems(List items) {
this.items = items;
}
public OrderState getOrderState() {
return orderState;
}
public void setOrderState(OrderState orderState) {
if (!getOrderState().isFinalized()){
this.orderState = orderState;
}
}
public void addItem(Item anItem){
if (getOrderState().canModify()){
getItems().add(anItem);
} else {
throw new IllegalStateException("Cannot add items to a closed order");
}
}
public void reOpen(){
if (!getOrderState().isFinalized()){
setOrderState(OrderState.OPEN);
}
}
}
public enum OrderState {
NEW("New",true,false),
OPEN("Open",true,false),
CLOSED("Closed",false,false),
SHIPPED("Shipped",false,true),
CANCELED("Canceled",false,true);
protected String name;
protected boolean finalized;
protected boolean modify;
private OrderState(String name, boolean canModify, boolean isFinalized){
this.name = name;
this.finalized= isFinalized;
this.modify = canModify;
}
public boolean canModify(){
return modify;
}
public boolean isFinalized(){
return finalized;
}
public String getName(){
return name;
}
}
状态越多,基于状态的逻辑越多,则从策略状态中获得的收益就越大。 策略状态使您的主要业务对象免受基于状态列表的增长的“ if语句”的影响。 另外,您还可以保留字符串的所有便利。 在此示例中,差异可能很小,但是随着域复杂性的增加,策略状态的好处也会增加。 另外,您曾经在复杂性没有增长的地方从事过哪个项目? 我的建议是始终从策略状态开始。 开销很小,随着项目复杂度的提高,您将感激不尽。
翻译自: https://www.javacodegeeks.com/2013/07/friends-dont-let-friends-use-string-states.html