【问题标题】:Handling code duplication in typescript code处理打字稿代码中的代码重复
【发布时间】:2017-09-06 11:49:38
【问题描述】:

我正在重构一个写得很糟糕的 Angular2 代码,它的服务方法如下:

  fooServiceName(body): Observable<any> {
    let headers = new Headers();
    this.loginService.writeAuthToHeaders(headers);
    return this.http.put(this.loginService.url() + '/url', body, { headers: headers })
    .map(response => response.json());
  }

  barResource(body): Observable<any> {
    let headers = new Headers();
    this.loginService.writeAuthToHeaders(headers);
    return this.http.post(this.loginService.url() + '/url', body, { headers: headers })
    .map(response => response.json());
  }

我看到以下几行在许多地方重复使用:

let headers = new Headers();
this.loginService.writeAuthToHeaders(headers);

我想写一个单独的方法来调用这些行,但问题是项目新手必须记住调用该方法,有没有更好的方法?

更新:

添加缺少的方法定义:

  /** function to write username and password to local storage of browser*/
  public writeAuthToHeaders(headers: Headers): void {
    headers.append('Accept', 'application/json');
    headers.append('Content-Type', 'application/json');
    headers.append('Authorization', 'Basic ' + btoa(getUsername() + ':' + this.getPassword()));
  }

【问题讨论】:

  • 但是任何刚接触该项目的人都需要知道调用这两行代码,所以我不知道记住是否是不将其粘贴在函数中的正当理由。
  • 每个有什么不同?只有url?
  • 从 Angular 4.3 开始,可以使用 interceptors 和新的 HttpClient。这是完成此类任务的合适场所

标签: typescript refactoring dry single-responsibility-principle


【解决方案1】:

如果类几乎相同,您可以编写一个复杂类型,并将差异传递给constructor。我写了以下作为例子:

Generic.Service.ts

import { Http } from '@angular/http';
import { Observable } from 'rxjs/Rx';

export class GenericService<T> {
    protected http: Http;

    constructor(private TCreator: { new (properties: any): T }, private url: string) {}

    public get(id: number): Observable<T> {
        return this.requestSingle(`${id}`);
    }

    public getAll(): Observable<T[]> {
        return this.requestMultiple('/all.json');
    }

    private requestSingle(addedUrl?: string): Observable<T> {
        return this.request(addedUrl)
        .map((response: Response) => new this.TCreator(response.json()));
    }

    private requestMultiple(addedUrl?: string): Observable<T[]> {
        return this.request(addedUrl)
        .map((response: Response) => {
            const results: any = response.json();
            for (let i = 0; i < results.length; i++) {
                results[i] = new this.TCreator(results[i]);
            }
            return results;
        });
    }

    private request(addedUrl?: string): Observable<any> {
        return this.http.get(this.url + (addedUrl ? addedUrl : ''));
    }
}

示例用法:

Vegetable.Service.ts

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';

import { GenericService } from './generic.service';
import { Vegetable } from '../app.component';

@Injectable()
export class VegetableService extends GenericService<Vegetable> {
    constructor(protected http: Http) {
        super(Vegetable, '/vegetables');
    }
}

Vegetable.ts

interface IVegetable {
  id: number;
  name: string;
  type: string;
}

export class Vegetable implements IVegetable {
  public id: number;
  public name: string;
  public type: string;

  constructor(properties: IVegetable) {
    this.id = properties.id;
    this.name = properties.name;
    this.type = properties.type;
  }
}

Some.Component.ts

import { Component, OnInit } from '@angular/core';

import { VegetableService } from './services/vegetable.service';
import { IVegetable } from '.components/vegetable.component';

@Component({
  selector: 'some-component',
  templateUrl: './some.component.html'
})
export class SomeComponent implements OnInit {
  public vegetables: IVegetable[] = [];

  constructor(private vegetableService: VegetableService) { ... }

  public ngOnInit(): void {
    ...
    this.vegetableService.getAll().subscribe((result) => this.vegetables = result);
    ...
  }
}

【讨论】:

  • 自定义注入器的用例是什么?
  • 但这会使测试变得困难,因为我们没有将它注入SomeComponent
  • 你会如何模拟GenericService?
  • 在这种情况下,这不是一个好的编码习惯,你应该先学习测试。
【解决方案2】:

最好是创建一个Gloabl service 共享所有常用方法,让我们假设您的问题

您可以为整个应用创建全局方法来执行相同的任务

 getHeaders(){
    let headers = new Headers();
    this.loginService.writeAuthToHeaders(headers);
    return headers;
 }

 fooServiceName(body): Observable<any> {
    return this.http.put(this.loginService.url() + '/url', body, { headers: this.getHeaders() })
    .map(response => response.json());
  }

  barResource(body): Observable<any> {
    return this.http.post(this.loginService.url() + '/url', body, { headers: this.getHeaders() })
    .map(response => response.json());
  }

还尝试为 CRUD 操作创建一些全局方法,以便在将来使用时尝试使用这些方法,而不是每次都创建新方法 只需将变量作为参数传递,例如url、data 等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-10
    • 2018-03-02
    • 2019-04-11
    • 2018-10-15
    • 2018-10-17
    • 2018-12-29
    • 2017-05-31
    • 2017-01-03
    相关资源
    最近更新 更多