我可以在 load 方法所在的位置有一个 VegetableManager(或其他东西)类,但这实际上意味着更少的重复代码吗?然后在每个屏幕中,我必须创建 VegetarianManager 的对象并调用它的加载方法。
这样做的重点不是效率(即性能)。关键是将加载该数据的细节封装到单个隔离对象中。例如,假设您的站点变得非常大,并且您决定将数据存储移动到数据库以实现可伸缩性和性能。在您描述的现有代码中,您必须遍历每个用户控件或页面并更改加载方法的逻辑。最好的情况是这很痛苦,最坏的情况是你错过了一些或复制粘贴不正确。如果逻辑被封装到一个专用对象中,其唯一职责就是知道如何从某个地方加载数据,那么您只需进行一次更改。
用户控制的代码隐藏:
protected void Page_Load(object sender, EventArgs e) {
var veggieManager = new VegetableManager();
VeggieListControl.DataSource = veggieManager.GetAll();
VeggieListControl.DataBind();
}
蔬菜管理器.cs:
public class VegetableManager {
private static Collection<Vegetable> _veggies;
private static object _veggieLock;
public ReadOnlyCollection<Vegetable> GetAll() {
if (_veggies == null) {
lock(_veggieLock) { //synchronize access to shared data
if (_veggies == null) { // double-checked lock
// logic to load the data into _veggies
}
}
}
return new ReadOnlyCollection(_veggies);
}
public void Add(Vegetable veggie) {
GetAll(); // call this to ensure that the data is loaded into _veggies
lock(_veggieLock) { //synchronize access to shared data
_veggies.Add(veggie);
// logic to write out the updated list of _veggies to the file
}
}
}
因为_veggies
是static
,内存中只有一个蔬菜集合,尽管多个调用者会实例化VegetableManager
。但是因为它是静态的,如果你有一个多线程的应用程序(例如一个网站),你必须在所有线程之间同步对那个字段的访问(因此是lock
s)。
就良好的面向对象而言,这是冰山一角。我建议仔细阅读 UncleBob 的 SOLID 原则和领域驱动设计(免费电子书)。
所以,是的,你在重复一些东西,但你重复的只是一个方法调用,重复一遍是可以的。DRY意味着减少“逻辑”代码的重复,即决策和算法;简单的方法调用不属于此范围。但是,如果您愿意,您可以将逻辑整合到一个基类中,从而有效地将用户控件与必须了解蔬菜管理器隔离开来,尽管我认为这是面向对象的过度杀伤力,或者 OOO :-)
public abstract class FoodUserControl : UserControl {
protected List<Vegetable> GetVeggies() {
return new VegetableManager().GetAll();
}
}
然后,您的实际控件将从此派生,而不是从 UserControl 派生。
更新
急切加载的 VegetableManager.cs:
public class VegetableManager {
private static Collection<Vegetable> _veggies;
private static object _veggieLock;
static VegetableManager() {
// logic to load veggies from file
}
public ReadOnlyCollection<Vegetable> GetAll() {
return new ReadOnlyCollection(_veggies);
}
public void Add(Vegetable veggie) {
lock(_veggieLock) { //synchronize access to shared data
_veggies.Add(veggie);
// logic to write out the updated list of _veggies to the file
}
}
}
请注意,此预加载版本不必在构造函数中围绕加载代码进行双重检查锁定。另请注意,加载代码位于static
构造函数中,因为此代码初始化了一个static
字段(否则,您将在每次构造时将文件中的数据重新加载到相同的共享static
字段中)。因为蔬菜是预先加载的,所以您不需要在 GetAll 或 Add 中加载。