質問

I'm trying to set up a good class diagram for my Angular application, however I have a problem figuring out how to solve the following situation:

I created a base Link class that can be used anywhere throughout the app. We have many flavors of links in the form of classes, RouterLink, ExternalLink, ClickLink (Links with click handlers applied to them). So every flavor/class derives from the base link class.

As I said, these classes can be used everywhere throughout the app, however, in some components in Angular, where we loop through a list of link classes, some of these classes need extra details that are only relevant to the component that it's in.

For example; We have a Sidebar component that needs one of the links to have a back icon behind it. We may have a component where we need to specify which Link class positions itself left or right. There could be many situations where we need variated Links tied to the component they are in.

How would you deal with this situation?

役に立ちましたか?

解決

I usually do the following. I define an interface LinkBase which contains all the fields that are common accross all types of links. This are things like label, icon, child nodes (, in your case probably link position or similar). Then I create an interface for each kind of link (normal href link, router link, action, label etc.). As last I define a type which is the union of all link kinds I have defined.

Here is an example:

export interface LinkBase {
    type: string;
    label: string;
    children?: Link[];
}

export interface LabelLink extends LinkBase {
    type: 'label';
}

export interface RouterLink extends LinkBase {
    type: 'routerLink';
    routerLink: string | string[];
}

export interface ActionLink extends LinkBase {
    type: 'action';
    action: () => any;
}

export type Link
    = LabelLink
    | RouterLink
    | ActionLink
    ;

My components that are responsible for displaying links simply accept Link objects. The components themselves are then responsible to decide on how to render each of those. You could implement one generic link component which you can use to render links in your content and you could for example have special handling in your navigation component.

So for your case you might consider adding the positioning configuration in the LinkBase interface, so all those settings apply to all kind of links you have implemented.

I hope this goes into the direction you were asking and gives you some ideas on how you could handle this.

Edit: Just to give you an example on the usage, this is how my nav-link component looks like:

import {Component, Input} from '@angular/core';
import {Link} from './link';

@Component({
  selector: 'app-nav-link',
  template: `
    <ng-template [ngIf]="isRouterLink">
      <a [routerLink]="routerLink"
         class="nav-link"
      >{{ label }}</a>
    </ng-template>
    <ng-template [ngIf]="isAction">
      <a href="javascript:void(0)"
         (click)="action()"
         class="nav-link"
      >{{ label }}</a>
    </ng-template>
  `,
})
export class NavLinkComponent {
  label: string;
  isRouterLink = false;
  isAction = false;
  routerLink: string | string[];
  action: () => any;

  @Input()
  set link(link: Link) {
    if (!link) {
      return;
    }
    this.label = link.label;
    if (link.type === 'routerLink') {
      this.isRouterLink = true;
      this.routerLink = link.routerLink;
    } else if (link.type === 'action') {
      this.isAction = true;
      this.action = link.action;
    }
  }
}

他のヒント

I think you could move all behaviour which are depend on context (where the link is rendered) into the separate 'strategies'.

Link provides public API (e.g. add/remove/change icon) which strategy could use in order to change the link. In terms of Angular it might be @Decorator which in constructor takes the Link instance and call link public methods. In addition one decorator might depends on other one which add high flexibility. That approach clearly seprates part which are vary on context and one which stay always the same.

It's simple example with suggested design https://stackblitz.com/edit/link-strategy

Slightly other variant might be implemented as "white box framework design". Where link take strategies as an input and call appropriate strategy methods (e.g. getIconName, getIconsPosition, -pre/-post redirects...)

ライセンス: CC-BY-SA帰属
所属していません softwareengineering.stackexchange
scroll top