Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 管理相同React.js类层次结构的OOP软件设计模式是什么?_Reactjs_Typescript_Oop_Design Patterns - Fatal编程技术网

Reactjs 管理相同React.js类层次结构的OOP软件设计模式是什么?

Reactjs 管理相同React.js类层次结构的OOP软件设计模式是什么?,reactjs,typescript,oop,design-patterns,Reactjs,Typescript,Oop,Design Patterns,我正在对React项目进行更改,这将产生许多类似的类,它们排列在相同的类层次结构中。我想知道我的代码可以使用什么替代组织 该产品当前显示的屏幕显示在店面终端上,店员和客户都将与之交互(一起阅读合同、收集双方签名等)。引入的更改是允许两个监视器设置,职员的班长将控制工作流程,客户的班长将跟进并在必要时请求输入。仍支持单监视器模式 代码目前有一个主合同签署窗口,带有可视组件,如文档查看器、签名捕获面板、带有合同详细信息的面板等。我想当两个监视器功能完成时,我将拥有三个几乎相同的类层次结构(或者更准确

我正在对React项目进行更改,这将产生许多类似的类,它们排列在相同的类层次结构中。我想知道我的代码可以使用什么替代组织

该产品当前显示的屏幕显示在店面终端上,店员和客户都将与之交互(一起阅读合同、收集双方签名等)。引入的更改是允许两个监视器设置,职员的班长将控制工作流程,客户的班长将跟进并在必要时请求输入。仍支持单监视器模式

代码目前有一个主合同签署窗口,带有可视组件,如文档查看器、签名捕获面板、带有合同详细信息的面板等。我想当两个监视器功能完成时,我将拥有三个几乎相同的类层次结构(或者更准确地说,相同的对象组成)。具有相同后缀的组件具有相同的用途,看起来几乎相同,但具有不同的行为

# Proposed object compositions
MainWindow has a DocumentViewer, and a SignaturePanel, and a DetailsPanel  
ClerkWindow has a ClerkDocumentViewer, and a ClerkSignaturePanel, and a ClerkDetailsPanel  
CustomerWindow has a CustomerDocumentViewer, and a CustomerSignaturePanel, and a CustomerDetailsPanel  
我担心这种模式的复杂性增长。当更多的组件添加到产品中时,我们将需要实现每个组件的三个版本;尽管可能性较小,但如果我们添加另一个“模式”,我们可能需要实现每个现有组件的新版本

此外,
Main
组件和
Clerk
组件非常相似,因为它们有很多控件供用户交互;但是“客户”组件的交互作用要小得多。我不确定如何在三个组件中的两个组件之间有效地共享代码。似乎很难正确组织的部分原因是因为这些是Typescript React组件,它们必须具有键入的状态和道具。如果要使用不同的DocumentViewer组件(例如)所有这些都继承自一个公共超类,我要么继承Customer组件中未使用的状态/道具,要么使用重复的代码管理Main和Clerk组件的公共状态/道具

我曾考虑过使用一个DocumentViewer(etc)类,该类具有一个
模式
属性,该属性控制组件在不同监视器设置上的行为,但组件最终将充满switch语句,这表明我需要类似上述的某种多态性


存在哪些设计模式来管理这些并行类层次结构?这些模式是否与React样式的状态/属性管理兼容?React/Typescript是否具有某种混合/模块功能,以允许将状态/属性有组织地共享给兄弟类的子集?

如前所述,这是一个脱离主题的问题,一个它与架构风格有关,而不仅仅是精确的解决方案或修复代码问题,无论回答与否,我都有点犹豫

但是,它仍然与特定的技术和生态系统相关,因此对于较小的社区来说可能过于狭窄。考虑到这一点,我将列出一些事情,您可以研究并缩小确切的问题


将所有共享代码提取到“哑”组件中 “dumb”组件并不是对主题中的表示组件的精确引用,而是遵循了类似的想法。在这种情况下,它们对您传递的特定类型一无所知,但知道如何处理任何共享逻辑或交互

这是您已经描述为一种潜在解决方案的东西,但您担心这些组件中有一堆switch case语句。避免这些条件语句的方法有:

  • 使传递给这些组件的数据尽可能相似或通用。只需说数据是一个具有id和签名对象的对象,就可以走很长的路
  • 所有特定于数据类型的处理程序和操作都应该从最顶层的组件(即“包装器”/“容器”)传递到该组件层次结构对于这些共享组件。作为一个简单的示例,假设您有一个带有垃圾图标的要删除的项目列表。在容器组件中,您将实现从列表状态中删除项目的逻辑,但其他交互(如单击处理程序和警告模式)将位于共享组件层次结构中
  • 如果任何交互是可选的,只需将这些属性设置为可选。在上面的示例中,如果删除是可选的,并且您没有传递delete属性,则共享组件知道不显示垃圾箱图标
  • 如果您有具有100%共享逻辑的可选交互(例如,是否使用了警告模式),请使用布尔属性作为标志。当您构建组件时,使用大量标志并不理想,但这是许多提供复杂表示组件(如表)的React库的一个常见功能
  • 如果您有特定的JSX元素或React组件需要在层次结构中一直呈现,那么没有什么可以阻止您将它们作为道具传递。记住,一切都是JavaScript中的一个对象。为了让同一个示例继续下去,这可以是警告模式的主体,如果该道具被传递,则可以覆盖该主体
  • 现在来看TypeScript部分。组件只是类或函数,您可以以相同的方式使用或函数,甚至将该泛型变量提供给子组件状态和props。您可以更具描述性地使用该泛型变量,并说它扩展了一个抽象类,以确保类型安全和性能将有关共享结构的更多信息传递给共享组件
  • 我将使用我在以下代码片段中滥用的示例,而不是您的用例,因为我不太确定您的组件和组件的实际实现的性质
    <SharedWindow>  // same for all objects => does not need a type variable
      <DocumentViewer<ClerkType> onSignature={this.handleSignature}> 
        {/* 
          DocumentViewer contains the Signature component that needs onSignature 
          which represents various needed handlers on that component or DocumentViewer
        */}
        <ClerkDetailsPanel/>  // specific Details component
      </DocumentViewer>
    </SharedWindow>
    
    export interface DocumentViewerProps<T> {
      // ...
    }
    
    export interface SignaturePanelProps<T> {
      // ...
    }
    
    export interface DetailsPanelProps<T> {
      // ...
    }
    
    export interface WindowProps<T> {
      DocumentViewer: ComponentType<DocumentViewerProps<T>>;
      SignaturePanel: ComponentType<SignaturePanelProps<T>>;
      DetailsPanel: ComponentType<DetailsPanelProps<T>>;
      // ...
    }
    
    export const Window = <T>({DocumentViewer, SignaturePanel, DetailsPanel}: WindowProps<T>) => {
      // do all shared window stuff
      
      return (
        <Screen>
           {needsSignature && (
              <SignaturePanel
                 // pass down all the right props, which depend on `T`
              />
           )}
           // do the same for <DocumentViewer /> and <DetailsPanel />
        </Screen>
      )
    }
    
    export interface Props<Settings> {
        initialSettings: Settings;
        RenderControls: ComponentType<{
            state: Settings;
            update(s: Partial<Settings>): void;
        }>;
        RenderContents: ComponentType<Settings & Size>;
        toolPadding?: number | string | Padding;
    }
    
    export const Tool = <Settings extends {}>({initialSettings, RenderControls, RenderContents, toolPadding = 0}: Props<Settings>) => {
        const [settings, update] = usePartialState<Settings>(initialSettings);
        const [ref, dimensions] = useDimensions();
        const {width = 0, height = 0, y = 0} = dimensions;
        const padding = padAmounts({width, toolPadding});
        const toolHeight = window.innerHeight - (Math.max(y, 0) + height + padding.top + padding.bottom);
        const toolWidth = width - (padding.left + padding.right);
    
        return (
            <div>
                <div ref={ref}>
                    <RenderControls
                        state={settings}
                        update={update}
                    />
                </div>
                <div style={{
                    paddingLeft: padding.left,
                    paddingRight: padding.right,
                    paddingTop: padding.top,
                    //don't include the bottom as a failsafe to prevent unnecessary scrolling
                }}>
                    <RenderContents
                        {...settings}
                        width={toolWidth}
                        height={toolHeight}
                    />
                </div>
            </div>
        )
    }
    
    export const HistogramTool = () => (
        <Tool
            initialSettings={{
                breakpoints: 6,
                group: randomGroup().name,
                channel: getChannel("hsl.l"),
            }}
            RenderControls={HistogramControls}
            RenderContents={GroupChannelHistogram}
            toolPadding={"10%"}
        />
    );