服务角度与自定义类?

时间:2021-01-20 20:29:49

标签: angular typescript software-design

我想知道创建服务的方法。

我从服务器 RegistryItem[] 以 JSON 格式获取数据。

选择创建处理每个 RegistryItem 的服务还是创建包含 class RegistryItemdelete() 之类的所有逻辑的 edit() 的方式?

class RegistryService {
   edit(registry);
   delete();
   drawRegister();
}

class RegistryItem {
    edit();
    delete();
    drawRegister();

    // Other logic for drawing registry
}

换句话说,我应该将响应项包装到逻辑类还是更好地将逻辑移动到特定服务?

2 个答案:

答案 0 :(得分:2)

我会选择单例服务。 所以无论你在哪里注入到应用程序中,你总是共享同一个服务实例(没有理由创建这个服务的多个实例)。 我们可以通过在可注入装饰器中的“根”或“平台”中提供它来实现这一点(参见下面的示例):

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Employee } from '../shared/employee';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})

export class RestApiService {
  
  // Define API
  apiURL = 'http://localhost:3000';

  constructor(private http: HttpClient) { }

  /*========================================
    CRUD Methods for consuming RESTful API
  =========================================*/

  // Http Options
  httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json'
    })
  }  

  // HttpClient API get() method => Fetch employees list
  getEmployees(): Observable<Employee> {
    return this.http.get<Employee>(this.apiURL + '/employees')
    .pipe(
      retry(1),
      catchError(this.handleError)
    )
  }

  // HttpClient API get() method => Fetch employee
  getEmployee(id): Observable<Employee> {
    return this.http.get<Employee>(this.apiURL + '/employees/' + id)
    .pipe(
      retry(1),
      catchError(this.handleError)
    )
  }  

  // HttpClient API post() method => Create employee
  createEmployee(employee): Observable<Employee> {
    return this.http.post<Employee>(this.apiURL + '/employees', JSON.stringify(employee), this.httpOptions)
    .pipe(
      retry(1),
      catchError(this.handleError)
    )
  }  

  // HttpClient API put() method => Update employee
  updateEmployee(id, employee): Observable<Employee> {
    return this.http.put<Employee>(this.apiURL + '/employees/' + id, JSON.stringify(employee), this.httpOptions)
    .pipe(
      retry(1),
      catchError(this.handleError)
    )
  }

  // HttpClient API delete() method => Delete employee
  deleteEmployee(id){
    return this.http.delete<Employee>(this.apiURL + '/employees/' + id, this.httpOptions)
    .pipe(
      retry(1),
      catchError(this.handleError)
    )
  }

  // Error handling 
  handleError(error) {
     let errorMessage = '';
     if(error.error instanceof ErrorEvent) {
       // Get client-side error
       errorMessage = error.error.message;
     } else {
       // Get server-side error
       errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
     }
     return throwError(errorMessage);
  }

}

这个例子不是我制作的,我取自这个guide。 但我很确定我会实现或多或少完全相同的代码,所以只需复制它。

只是对代码的一些评论:

我不会在服务中定义 API URL 端点,您可能需要访问来自不同环境(例如 local/QA/prod)的不同 API,因此我会将端点作为字符串存储在环境文件中(例如environment.[targetENV].ts) 由 Angular CLI 自动创建。当然,如果您计划从每个 ENV 访问始终相同的 API,您可以完全按照示例进行操作。否则,您可以为您拥有的每个环境文件分配一个不同的 API 端点,然后将其导入您的服务以使用它。 ENV 文件截图:

example image of env files

这是您可能希望如何构建 env 文件的示例。

export const environment = {
production: false,
API_URL: 'http:/blabla.com/blabla/api',
API_EMPLOYEE: 'http://test.api.com/test-api/api',

};

如果您的代码可能在一个运行多个 Angular 应用程序的网页上使用,您可能希望在“平台”而不是“根”中提供它。 100% 只使用一个服务实例。

要实现这一点,只需从以下位置更改可注入装饰器:

@Injectable({
  providedIn: 'root'
})

到:

@Injectable({
  providedIn: 'platform'
})

答案 1 :(得分:1)

最佳实践要求您将模型和业务逻辑分开。你的模型(类型或接口)应该只执行数据没有任何行为,你可以注入kind: Deployment apiVersion: apps/v1 metadata: name: jetty namespace: default spec: replicas: 1 selector: matchLabels: app: jetty template: metadata: labels: app: jetty spec: containers: - name: jetty image: quay.io/user/jetty ports: - containerPort: 8080 volumeMounts: - name: config-properties mountPath: "/opt/jetty/config.properties" subPath: config.properties - name: secrets-properties mountPath: "/opt/jetty/secrets.properties" - name: doc-path mountPath: /mnt/storage/ resources: limits: cpu: '1000m' memory: '3000Mi' requests: cpu: '750m' memory: '2500Mi' volumes: - name: config-properties configMap: name: jetty-config-properties - name: secrets-properties secret: secretName: jetty-secrets - name: doc-path persistentVolumeClaim: claimName: jetty-docs-pvc imagePullSecrets: - name: rcc-quay 来操纵你的模型:

services

并且您的服务应包含与操作您的 export interface RegistryItem { id: number; // other related properties } 相关的逻辑:

RegistryItem

此服务可以稍后注入并在您的组件中使用,例如 follow

registry-item.component.ts

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

@Injectable({
  providedIn: 'root',
})
export class RegistryItemService {
// your backend base api url
baseUrl = 'http://localhost:3000/api';
getAll() : Observable<RegistryItem[]> {
   return this.http.get<RegistryItem[]>(this.baseUrl+ '/registry-items')
}
update(item: RegistryItem) : Observable<RegistryItem> {...}
create(item: RegistryItem) : Observable<any> {...}
delete(id: number) : Observable<any> {...}
drawRegister() {...};
}

registry-item.component.html

@Component({
  selector: 'app-registry-item',
  templateUrl: './registry-item.component.html',
})
export class RegistryItemComponent {
  registryItems: RegistryItem[] = [];
  constructor(private service: RegistryItemService ) { 
    this.service.getAll().subscribe(res=>  {
            this.registryItems = res;
           },
         err=> console.error(err)
      );
  }

}