每个 knockoutjs 模板有一个单独的 VM class 违反了 OOP?

Having a separate VM class per knockoutjs template violates OOP?

我已经多次看到网页的特定区域有多个模板,根据场景加载其中一个模板。通常,相应的 VM 在该点实例化并绑定到模板。

这种设计模式是否不违反 OOP 原则,因为对象(在本例中为 VM)应该基于实际存在的功能实体,而不一定基于 UI 的特定区域。

让我用一个例子来证实这一点。假设我们有一个网页处理衣服、鞋子和家具的在线销售。一旦 selection 在页面的特定部分中的三个中创建,一个单独的模板将加载到页面的另一部分,这取决于 selection 所做的。根据 OOP 规则,我的对象模型应该是 ItemVM<-ShoeVM,ClothesVM,FurntitureVM,还是应该是包含 ItemSelectorVM(对于 UI 到 select 项目类型)、shoeAdverisementVM(绑定到结果加载了鞋子模板)、FurnitureAdvertisementVM 以及页面每个部分的更多 VM?

当你说 OOP 原则时,我假设你指的是 SOLID

View Models 为 UI 建模,不必耦合到单个模板。您可以将视图模型与已创建的目标桌面模板一起使用,然后将视图模型与已创建的目标移动设备模板一起使用。

Should my object model be ItemVM<-ShoeVM,ClothesVM,FurntitureVM as per OOP rules, or should it be ParentVM containing ItemSelectorVM (for the UI to select the item type), shoeAdverisementVM (to bind to the shoe template loaded as a result), FurnitureAdvertisementVM and many more VMs for every part of the page?

这取决于应用程序和域的复杂性。

让我们假设您的 UI 不只是迭代 ObservableArray<T>,其中 T 可能是 ShoeFurniture 类型。我们还假设 ShoeAdvertisementVM 不是 ItemVM<T>decorator

现在,假设您有 FurnitureAdvertisementVMShoeAdverisementVM,如下所示:

function FurnitureAdvertisementVM(furniture){
   this.items = ko.observableArray(furniture);
   this.doSomething = function(){
      // doing something
   }
}

function ShoeAdverisementVM(shoes){
   this.items = ko.observableArray(shoes);
   this.doSomething = function(){
      // doing something
   }
}

var shoeVM = new ShoeAdverisementVM(shoes);
var furnitureVM = new FurnitureAdverisementVM(furniture);

如果这两个视图模型几乎是一个复制和粘贴工作,唯一的区别是视图模型的名称和进入集合的项目的类型,那么可能值得将实现更改为通用的东西像这样:

function ItemsVM(items){
   this.items = ko.observableArray(items);
   this.doSomething = function(){
      // doing something
   }
}

var shoeVM = new ItemsM(shoes);
var furnitureVM = new ItemsVM(furniture);

但是如果每个视图模型都有一些非常具体的属性和功能,例如:

function FurnitureAdvertisementVM(furniture, someOtherDependency){
   this.items = ko.observableArray(furniture);
   this.doSomething = function(){
      // doing something
   }
   this.propertyIsBoundToATextbox = ko.observable();
   this.clickHandlerUsesDependency = function(ctx){
      if(ctx.SomeCondition){
         someOtherDependency.doSomething();
      }
   }
}

function ShoeAdverisementVM(shoes){
   this.items = ko.observableArray(shoes);
   this.doSomething = function(){
      // doing something
   }
   this.propertyIsBoundToACheckbox = ko.observable();
}

然后它不像使两个视图模型通用那样清晰。

Roy J 评论:

your viewmodels are intended to model the view (the UI)

这是真的,所以如果视图有不同的要求,即一个有 3 个复选框,另一个有大量按钮等,那么您可能需要不同的视图模型。

如果您想将一些常用功能分解为单独的 类,那么您可以:

function ItemService(items){
   this.items = ko.observableArray(items);
   this.doSomething = function(){
      // doing something
   }
}

function FurnitureAdvertisementVM(itemService, someOtherDependency){
   this.service = itemService;
   this.propertyIsBoundToATextbox = ko.observable();
   this.clickHandlerUsesDependency = function(ctx){
      if(ctx.SomeCondition){
         someOtherDependency.doSomething();
      }
   }
}

function ShoeAdverisementVM(itemService){
   this.service = itemService;
   this.propertyIsBoundToACheckbox = ko.observable();
}