爱一个人最好的方式,是经营好自己,给对方一个优质的爱人,不是拼命对一个人好,那人就会拼命爱你
状态模式是一种行为设计模式,用于解决当对象的行为依赖于其内部状态时可能出现的复杂条件逻辑问题。状态模式通过将每个状态的行为封装在独立的状态类中,使对象在内部状态改变时能够改变其行为。这样可以降低代码的复杂性,提高可维护性和可扩展性。
假设我们有一个简单的交通信号灯系统,信号灯有三种状态:红灯、黄灯和绿灯。根据不同的状态,信号灯的行为会有所不同。例如,当信号灯为红灯时,汽车应该停止;当信号灯为绿灯时,汽车可以通行。
不使用状态模式的情况下,我们可能会使用复杂的条件逻辑来处理这个问题:
public class TrafficLight {
private String state;
public void setState(String state) {
this.state = state;
}
public void handle() {
if ("red".equalsIgnoreCase(state)) {
System.out.println("停止");
} else if ("yellow".equalsIgnoreCase(state)) {
System.out.println("准备");
} else if ("green".equalsIgnoreCase(state)) {
System.out.println("通行");
}
}
}
public interface TrafficLightState {
void handle();
}
public class RedLightState implements TrafficLightState {
@Override
public void handle() {
System.out.println("停止");
}
}
public class YellowLightState implements TrafficLightState {
@Override
public void handle() {
System.out.println("准备");
}
}
public class GreenLightState implements TrafficLightState {
@Override
public void handle() {
System.out.println("通行");
}
}
public class TrafficLight {
private TrafficLightState state;
public void setState(TrafficLightState state) {
this.state = state;
}
public void handle() {
state.handle();
}
}
public class Client {
public static void main(String[] args) {
TrafficLight trafficLight = new TrafficLight();
trafficLight.setState(new RedLightState());
trafficLight.handle();
trafficLight.setState(new YellowLightState());
trafficLight.handle();
trafficLight.setState(new GreenLightState());
trafficLight.handle();
}
}
尽管状态模式可能导致类数量增加,但它的优点在于它解决了代码维护和扩展的问题,尤其是在处理复杂状态转换和状态间行为差异较大的情况下。
当对象的行为依赖于其内部状态,并且随着状态的改变而改变时,可以考虑使用状态模式。此外,当状态转换逻辑复杂时,使用状态模式可以简化代码结构。
如果你发现你的代码中有大量的 if-else 或 switch-case 语句,用于处理不同状态下的行为,这是一个信号,表明你可以考虑使用状态模式进行重构。
在实现状态模式时,遵循单一职责原则,将每个状态的行为封装在单独的状态类中。这有助于将不同状态的行为逻辑分离,使代码更易于理解和维护。
状态模式可以与其他设计模式结合使用,例如:工厂模式,用于创建和管理状态类的实例;策略模式,用于处理不同状态类之间的相似行为。
如果状态类之间有共享的行为或数据,可以考虑使用状态类之间的继承关系。这可以避免代码重复,提高代码复用性。
优点:
缺点:
在实际应用中,你应该根据项目的具体需求和复杂性来判断是否使用状态模式。如果状态之间的转换逻辑比较简单,而且状态数量有限,那么引入状态模式可能并不是一个最佳选择。然而,在面对复杂的状态转换逻辑和多个状态时,状态模式可以帮助你降低代码的复杂度,提高代码的可读性和可维护性。
策略模式是一种行为设计模式,它允许你在运行时根据需要切换不同的算法或策略。策略模式通过定义一系列可互换的算法,并将它们封装成独立的策略类。这使得代码更易于理解、更具可扩展性,并且遵循开放/封闭原则。
例子:
假设我们正在开发一个电商平台,该平台支持多种不同的折扣策略,如新用户折扣、会员折扣等。我们希望在运行时根据不同的用户和购物情况选择合适的折扣策略。
不使用策略模式的情况下,我们可能会使用复杂的条件逻辑来处理这个问题:
public class DiscountCalculator {
public double calculateDiscount(String userType, double originalPrice) {
double discount = 0;
if ("newUser".equalsIgnoreCase(userType)) {
discount = originalPrice * 0.1;
} else if ("member".equalsIgnoreCase(userType)) {
discount = originalPrice * 0.15;
} // 更多折扣类型
return discount;
}
}
使用策略模式重构此代码:
public interface DiscountStrategy {
double calculateDiscount(double originalPrice);
}
public class NewUserDiscount implements DiscountStrategy {
@Override
public double calculateDiscount(double originalPrice) {
return originalPrice * 0.1;
}
}
public class MemberDiscount implements DiscountStrategy {
@Override
public double calculateDiscount(double originalPrice) {
return originalPrice * 0.15;
}
}
public class DiscountCalculator {
private DiscountStrategy discountStrategy;
public void setDiscountStrategy(DiscountStrategy discountStrategy) {
this.discountStrategy = discountStrategy;
}
public double calculateDiscount(double originalPrice) {
return discountStrategy.calculateDiscount(originalPrice);
}
}
public class Client {
public static void main(String[] args) {
DiscountCalculator calculator = new DiscountCalculator();
// 新用户折扣
calculator.setDiscountStrategy(new NewUserDiscount());
System.out.println("新用户折扣:" + calculator.calculateDiscount(100));
// 会员折扣
calculator.setDiscountStrategy(new MemberDiscount());
System.out.println("会员折扣:" + calculator.calculateDiscount(100));
}
}
解决的问题:
限制:
尽管状态模式和策略模式在结构上非常相似,都包括上下文类、接口和一组实现接口的具体类,但它们的目的和使用场景有所不同。
目的:状态模式主要用于处理对象在不同状态下的行为,其目的是简化复杂的状态转换逻辑。策略模式主要用于在运行时切换不同的算法或策略,其目的是提高代码的可扩展性和可维护性。
状态与策略的切换:在状态模式中,状态的切换通常是由状态类自身控制的,即状态类决定何时以及如何切换到另一个状态。而在策略模式中,策略的切换通常由客户端代码或上下文类控制。
使用场景:状态模式适用于对象的行为取决于其内部状态的情况,例如交通信号灯、订单状态等。策略模式适用于需要在运行时根据不同的需求或条件选择不同算法的情况,例如折扣计算、排序算法等。
总结一下,状态模式和策略模式在结构上非常相似,但它们的目的和使用场景有所不同。状态模式主要用于简化复杂的状态转换逻辑,而策略模式主要用于提高代码的可扩展性和可维护性。在实际应用中,你应该根据项目的具体需求和场景来选择合适的设计模式。
状态模式 中,状态的切换是由状态类自身控制的。这意味着状态对象可以在某个操作执行后,根据内部逻辑来决定是否切换到另一个状态。这样,上下文类不需要知道状态间的转换逻辑,它只需要将操作委托给当前状态对象。例如,在交通信号灯的例子中,我们可以在每个状态类中添加一个方法来处理状态的切换:
public interface TrafficLightState {
void handle();
void switchState(TrafficLight trafficLight);
}
public class RedLightState implements TrafficLightState {
// ...
@Override
public void switchState(TrafficLight trafficLight) {
trafficLight.setState(new GreenLightState());
}
}
public class GreenLightState implements TrafficLightState {
// ...
@Override
public void switchState(TrafficLight trafficLight) {
trafficLight.setState(new YellowLightState());
}
}
public class YellowLightState implements TrafficLightState {
// ...
@Override
public void switchState(TrafficLight trafficLight) {
trafficLight.setState(new RedLightState());
}
}
这样,上下文类只需要调用当前状态对象的 switchState
方法,就可以实现状态的切换:
public class TrafficLight {
// ...
public void switchState() {
state.switchState(this);
}
}
策略模式 中,策略的切换通常由客户端代码或上下文类控制。这意味着策略类通常不知道其他策略的存在,也不会自己切换到其他策略。客户端代码或上下文类会根据不同的需求或条件,选择合适的策略并设置给上下文类。例如,在折扣计算的例子中,客户端代码可以根据用户类型来选择合适的折扣策略:
public class Client {
public static void main(String[] args) {
DiscountCalculator calculator = new DiscountCalculator();
String userType = "member"; // 可以从其他地方获取用户类型
if ("newUser".equalsIgnoreCase(userType)) {
calculator.setDiscountStrategy(new NewUserDiscount());
} else if ("member".equalsIgnoreCase(userType)) {
calculator.setDiscountStrategy(new MemberDiscount());
}
System.out.println("折扣:" + calculator.calculateDiscount(100));
}
}
可以在策略接口中添加一个方法(例如 method1
),用于判断当前策略是否适用于特定条件。然后,在上下文类中,可以循环遍历所有可用策略,根据 method1
的结果选择合适的策略。这种方法可以使策略选择的逻辑更加集中,简化客户端代码。
首先,我们在策略接口中添加 method1
方法:
public interface DiscountStrategy {
double calculateDiscount(double originalPrice);
boolean isApplicable(String userType);
}
然后,在具体策略类中实现 method1
:
public class NewUserDiscount implements DiscountStrategy {
// ...
@Override
public boolean isApplicable(String userType) {
return "newUser".equalsIgnoreCase(userType);
}
}
public class MemberDiscount implements DiscountStrategy {
// ...
@Override
public boolean isApplicable(String userType) {
return "member".equalsIgnoreCase(userType);
}
}
接下来,我们修改上下文类,使其可以接收一组策略,并根据 method1
的结果选择合适的策略:
public class DiscountCalculator {
private List<DiscountStrategy> discountStrategies;
public DiscountCalculator(List<DiscountStrategy> discountStrategies) {
this.discountStrategies = discountStrategies;
}
public void setDiscountStrategies(List<DiscountStrategy> discountStrategies) {
this.discountStrategies = discountStrategies;
}
public double calculateDiscount(String userType, double originalPrice) {
for (DiscountStrategy strategy : discountStrategies) {
if (strategy.isApplicable(userType)) {
return strategy.calculateDiscount(originalPrice);
}
}
return 0; // 无折扣
}
}
最后,客户端代码可以将所有可用策略传递给上下文类,然后调用 calculateDiscount
方法:
public class Client {
public static void main(String[] args) {
List<DiscountStrategy> strategies = Arrays.asList(new NewUserDiscount(), new MemberDiscount());
DiscountCalculator calculator = new DiscountCalculator(strategies);
String userType = "member"; // 可以从其他地方获取用户类型
System.out.println("折扣:" + calculator.calculateDiscount(userType, 100));
}
}
通过这种方式,我们可以将策略选择的逻辑封装在上下文类中,简化客户端代码。
状态模式和策略模式在状态/策略切换方面的主要区别在于:
在状态模式中,状态的切换通常是由状态类自身控制的,状态类决定何时以及如何切换到另一个状态;
状态之间可以感知其他状态实现
而在策略模式中,策略的切换通常由客户端代码或上下文类控制,它们根据不同的需求或条件来选择合适的策略。
策略之间互相不知道, 通常可以在策略类增加一个方法 isApplicable 判断符合当前条件是否满足当前执行策略, 在上下文中循环判断 isApplicable 是否满足条件