Angular 2工厂模式实现及模板复用、按需构建配置咨询
Hey there! Great question—combining factory patterns with reusable templates in Angular 2 (now part of the broader Angular ecosystem) is a smart way to keep your code DRY and scalable. Let’s break this down into three key areas to solve your problem:
For your use case (common elements like tires/windows plus exclusive features for cars/buses/trucks), content projection (using <ng-content>) is the most flexible approach to reuse a base template while injecting custom content. Here’s how to set it up:
Step 1: Create a Base Vehicle Component
This component holds all your shared UI and logic:
// vehicle-base.component.ts import { Component, Input } from '@angular/core'; @Component({ selector: 'app-vehicle-base', template: ` <div class="vehicle-container"> <!-- Shared UI Elements --> <div class="shared-features"> <h3>General Vehicle</h3> <p>Tires: {{ tireCount }}</p> <p>Windows: {{ windowCount }}</p> <button (click)="rollUpAllWindows()">Roll Up Windows</button> </div> <!-- Slot for Vehicle-Specific Content --> <div class="specific-features"> <ng-content></ng-content> </div> </div> `, styles: [` .vehicle-container { border: 1px solid #eee; padding: 1rem; margin: 1rem 0; } .shared-features { background: #f5f5f5; padding: 0.5rem; margin-bottom: 1rem; } `] }) export class VehicleBaseComponent { @Input() tireCount: number; @Input() windowCount: number; rollUpAllWindows() { console.log("All windows rolled up!"); // Add shared window control logic here } }
Step 2: Build Vehicle-Specific Components
Each vehicle component will wrap the base component and inject its own exclusive UI/logic:
// car.component.ts import { Component } from '@angular/core'; @Component({ selector: 'app-car', template: ` <app-vehicle-base [tireCount]="4" [windowCount]="4"> <!-- Car-Exclusive Content --> <h4>Car Features</h4> <p>Doors: 4</p> <button (click)="activateCruiseControl()">Enable Cruise Control</button> </app-vehicle-base> ` }) export class CarComponent { activateCruiseControl() { console.log("Cruise control activated!"); // Add car-specific logic here } }
Repeat this pattern for BusComponent (e.g., add passenger door controls) and TruckComponent (e.g., trailer hitch controls)—all reusing the base template’s shared elements.
Since you already know TypeScript’s factory basics, let’s adapt this to Angular’s dependency injection (DI) system (critical for managing services/components with dependencies):
Step 1: Define a Vehicle Interface
Create a contract for all vehicle types:
// vehicle.interface.ts export interface Vehicle { getVehicleType(): string; activateSpecialFeature(): void; }
Step 2: Build Vehicle Services
Each vehicle type gets its own service implementing the interface:
// car.service.ts import { Injectable } from '@angular/core'; import { Vehicle } from './vehicle.interface'; @Injectable() export class CarService implements Vehicle { getVehicleType(): string { return "Car"; } activateSpecialFeature(): void { console.log("Car: Activating cruise control!"); } }
Do the same for BusService and TruckService with their unique features.
Step 3: Create the Vehicle Factory
Use Angular’s Injector to instantiate services (avoids manual new calls which break DI):
// vehicle-factory.service.ts import { Injectable, Injector } from '@angular/core'; import { Vehicle } from './vehicle.interface'; import { CarService } from './car.service'; import { BusService } from './bus.service'; import { TruckService } from './truck.service'; @Injectable() export class VehicleFactoryService { constructor(private injector: Injector) {} createVehicle(type: string): Vehicle { switch(type) { case "car": return this.injector.get(CarService); case "bus": return this.injector.get(BusService); case "truck": return this.injector.get(TruckService); default: throw new Error(`Unknown vehicle type: ${type}`); } } }
Step 4: Use the Factory in a Component
// vehicle-manager.component.ts import { Component } from '@angular/core'; import { VehicleFactoryService } from './vehicle-factory.service'; import { Vehicle } from './vehicle.interface'; @Component({ selector: 'app-vehicle-manager', template: ` <button (click)="createVehicle('car')">Spawn Car</button> <button (click)="createVehicle('bus')">Spawn Bus</button> <button (click)="createVehicle('truck')">Spawn Truck</button> <p *ngIf="currentVehicle">Active Vehicle: {{ currentVehicle.getVehicleType() }}</p> ` }) export class VehicleManagerComponent { currentVehicle: Vehicle; constructor(private vehicleFactory: VehicleFactoryService) {} createVehicle(type: string) { this.currentVehicle = this.vehicleFactory.createVehicle(type); this.currentVehicle.activateSpecialFeature(); } }
To split your app into modular chunks (for faster loads and better maintainability), use Angular’s built-in lazy loading and chunk splitting:
Lazy Load Vehicle Modules
Organize each vehicle type into its own module, then configure routing to load them on demand:
// app-routing.module.ts import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = [ { path: 'car', loadChildren: () => import('./car/car.module').then(m => m.CarModule) }, { path: 'bus', loadChildren: () => import('./bus/bus.module').then(m => m.BusModule) }, { path: 'truck', loadChildren: () => import('./truck/truck.module').then(m => m.TruckModule) }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule {}
Fine-Tune Chunk Splitting
In your angular.json config, you can customize how chunks are split (e.g., group shared code into a single chunk):
{ "projects": { "your-app-name": { "architect": { "build": { "options": { "optimization": true, "splitChunks": { "chunks": "all", "cacheGroups": { "vehicle-shared": { "test": /[\\/]vehicle-base[\\/]/, "name": "vehicle-shared", "chunks": "all" } } } } } } } } }
This will bundle all shared vehicle base code into a separate vehicle-shared.js chunk, which is reused across all vehicle modules.
内容的提问来源于stack exchange,提问作者Veena Mohan

