C#状态模式中父类变量定义与初始化:子类共享变量如何从主类赋值
嘿,我完全懂你现在的处境——在状态模式里折腾共享变量,想在抽象父类里定义一次让所有子类复用,但主类怎么初始化这些protected变量又拿不准,还要应付数量不固定的子类对吧?别慌,我给你几个实用的解决方案,都是在实际开发中验证过的:
首先得说,别想着让主类直接去改父类的protected变量——这既不符合封装原则,跨包的话还根本访问不了。更好的思路是让父类自己管理共享变量,主类只需要通过父类提供的“入口”来初始化,子类自动继承复用。
方案1:构造函数注入(适合每个状态实例需要独立共享变量的场景)
如果你的共享变量是每个状态实例初始化时确定的,把它们放到父类的构造函数里,子类创建时调用父类构造传递参数就行。这样不管子类有多少个,都只需要在父类定义一次变量:
// 抽象父类:管理共享变量,定义构造方法 abstract class BaseStep { protected String sharedConfig; protected int sharedCounter; // 父类构造:接收初始化参数,给共享变量赋值 public BaseStep(String sharedConfig, int sharedCounter) { this.sharedConfig = sharedConfig; this.sharedCounter = sharedCounter; } // 子类必须实现的抽象方法 public abstract void execute(); } // 子类1:调用父类构造,自动继承共享变量 class Step01 extends BaseStep { public Step01(String sharedConfig, int sharedCounter) { super(sharedConfig, sharedCounter); } @Override public void execute() { System.out.println("Step01执行 | 配置:" + sharedConfig + " | 计数器:" + sharedCounter); } } // 子类2:同理,不用重复定义变量 class Step02 extends BaseStep { public Step02(String sharedConfig, int sharedCounter) { super(sharedConfig, sharedCounter); } @Override public void execute() { sharedCounter++; // 子类可以修改共享变量 System.out.println("Step02执行 | 配置:" + sharedConfig + " | 计数器:" + sharedCounter); } } // 主类:初始化变量,传递给子类构造 public class StateDemo { public static void main(String[] args) { // 先初始化共享变量 String globalConfig = "系统全局配置V1.0"; int initCounter = 0; // 创建子类时,把变量传给父类构造 BaseStep step1 = new Step01(globalConfig, initCounter); BaseStep step2 = new Step02(globalConfig, initCounter); step1.execute(); step2.execute(); } }
方案2:静态共享变量(适合所有子类实例共用同一组变量的场景)
如果你的共享变量是全局通用的(比如所有状态实例都用同一个配置、同一个计数器),把父类的变量设为static protected,然后在父类加一个静态初始化方法,主类直接调用就行——这样不管子类有多少,都共享同一组变量:
// 抽象父类:静态共享变量+初始化方法 abstract class BaseStep { // 静态变量:所有子类实例共用 protected static String sharedGlobalConfig; protected static int sharedGlobalCounter; // 静态初始化方法:主类调用这个方法来赋值 public static void initSharedVars(String config, int counter) { sharedGlobalConfig = config; sharedGlobalCounter = counter; } public abstract void execute(); } // 子类1:直接用父类的静态变量,不用传参 class Step01 extends BaseStep { @Override public void execute() { System.out.println("Step01执行 | 全局配置:" + sharedGlobalConfig + " | 全局计数器:" + sharedGlobalCounter); } } // 子类2:修改静态变量后,所有子类都会看到变化 class Step02 extends BaseStep { @Override public void execute() { sharedGlobalCounter++; System.out.println("Step02执行 | 全局配置:" + sharedGlobalConfig + " | 全局计数器:" + sharedGlobalCounter); } } // 主类:调用父类静态方法初始化 public class StateDemo { public static void main(String[] args) { // 一步搞定所有子类的共享变量初始化 BaseStep.initSharedVars("全局共享配置V2.0", 0); BaseStep step1 = new Step01(); BaseStep step2 = new Step02(); step1.execute(); // 计数器0 step2.execute(); // 计数器1 step1.execute(); // 计数器1(因为静态变量被修改了) } }
方案3:抽离共享状态类(最优雅,适合复杂共享逻辑)
如果共享变量比较多、逻辑复杂,或者不想用静态变量(避免全局状态的副作用),可以把共享变量抽成一个独立的类,然后把这个类的实例传递给每个子类——这样所有子类共享同一个状态实例,修改时所有子类都会同步:
// 单独的共享状态类:封装所有共享变量和操作 class SharedState { private String config; private int counter; public SharedState(String config, int counter) { this.config = config; this.counter = counter; } // getter/setter,封装变量操作 public String getConfig() { return config; } public void setConfig(String config) { this.config = config; } public int getCounter() { return counter; } public void incrementCounter() { this.counter++; } } // 抽象父类:持有共享状态实例 abstract class BaseStep { protected SharedState sharedState; public BaseStep(SharedState sharedState) { this.sharedState = sharedState; } public abstract void execute(); } // 子类1:通过sharedState访问共享变量 class Step01 extends BaseStep { public Step01(SharedState sharedState) { super(sharedState); } @Override public void execute() { System.out.println("Step01执行 | 配置:" + sharedState.getConfig() + " | 计数器:" + sharedState.getCounter()); } } // 子类2:修改共享状态,所有子类同步 class Step02 extends BaseStep { public Step02(SharedState sharedState) { super(sharedState); } @Override public void execute() { sharedState.incrementCounter(); System.out.println("Step02执行 | 配置:" + sharedState.getConfig() + " | 计数器:" + sharedState.getCounter()); } } // 主类:创建共享状态实例,传递给所有子类 public class StateDemo { public static void main(String[] args) { // 初始化共享状态实例 SharedState sharedState = new SharedState("组合式共享配置", 0); // 所有子类共用同一个sharedState BaseStep step1 = new Step01(sharedState); BaseStep step2 = new Step02(sharedState); step1.execute(); // 计数器0 step2.execute(); // 计数器1 step1.execute(); // 计数器1 } }
为什么不推荐主类直接改protected变量?
protected的可见性是“包内+子类”,如果主类和父类不在同一个包,根本访问不了;就算在同一个包,直接修改会破坏封装——父类的变量逻辑被分散到主类里,后期维护时你根本不知道哪里改了这些变量,很容易出bug。上面的方案都遵循了封装原则,主类只负责初始化,子类只负责使用,父类(或独立状态类)负责管理变量逻辑。
内容的提问来源于stack exchange,提问作者Mr. Knackwurst

