What is the difference between concrete factories and abstract factories?
PS: I originally asked a question "what is a concrete factory". Asked my doubt here in a separated question to keep the two discussions separate.
The thing is abstract factories are just abstract class the concrete factories give the real implementation of the abstract classes
The difference will be easier to see from the perspective of a client class which makes use of the factory class.
If the client class uses a concrete factory class, then it will be difficult to reuse the client class in another context. We cannot replace the current in-used concrete factory class by another concrete factory class without modifying source code of the client class.
In contrast, if the client uses an abstract factory class (or interface), we can easily reuse the client class with another (concrete) factory class because the source code of the client class does not mention any concrete factory class. For example, consider the code below:
interface AbstractFactory { Product create(); }
class Client {
private AbstractFactory factory;
public Client(AbstractFactory factory) { this.factory = factory; }
public void foo() { /* use this.factory */ }
}
// Now we can reuse the Client class with any concrete factory class
class ConcreteFactory1 implements AbstractFactory { ... }
class ConcreteFactory2 implements AbstractFactory { ... }
Client client1 = new Client(new ConcreteFactory1());
client1.foo();
Client client2 = new Client(new ConcreteFactory2());
client2.foo();
As you see, in any case, source code of the Client class does not need to be modified, but it still works with different concrete factory class.
Related
Using DI in components works great with inject (#inject or in Codebehind with [inject]).
Now how does it work if you want to use DI in a normal class? I found exactly the same question here:
Blazor - Call JavaScript from C# class
Unfortunately, although the question is marked as answered, it is not clear how this is actually supposed to work. I'll summarize it here:
you create a class which should be used as DI, here for example for JSInterop (e.g. to use JavaScript outside from components):
public class JsInteropForClasses
{
private readonly IJSRuntime jSRuntime;
public JsInteropForClasses(IJSRuntime jSRuntime)
{
this.jSRuntime = jSRuntime;
}
public async void MessageBox()
{
await jSRuntime.InvokeVoidAsync("MessageBox", "DI question!!!");
}
}
you register service in Program.cs
builder.Services.AddTransient<JsInteropForClasses>();
and now comes the crucial question, how do you use this in a other class that is not a component (so where you can't use inject)?
I applied the suggested solution, but I get argument problem because constructor of DI-class expects an object type IJSRuntime and I don't pass anything during creation:
JsInteropForClasses js = new JsInteropForClasses();
js.MessageBox();
Therefore, I can't use DI (because program can't start).
The following variant does not work either:
JsInteropForClasses js;
js.MessageBox();
I searched for a long time, but only found this one entry (see link). All others refer to DI and components.
Does anyone know about how to use DI in own class (not components)?
Thanks
When you register a service in the DI container (in Program.cs) initialization of the service will be handled by the DI. That means you should NOT call the constructor on your own. The only thing you need to do is to register the service (with the interface if necessary) properly. Like this:
builder.Services.AddTransient<JsInteropForClasses>();
or
builder.Services.AddTransient<IJsInteropForClasses, JsInteropForClasses>();
Then you can inject the service (or interface of the service) in the class constructor you want to use.
Like:
public class SomeClass {
private readonly JsInteropForClasses jsInteropForClasses;
public SomeClass(JsInteropForClasses jsInteropForClasses) {
this.jsInteropForClasses = jsInteropForClasses;
}
}
or in Razor as shown by Henk here
#inject JsInteropForClasses ij
I have an Angular application that interacts with several REST APIs. There is some common logic when sending requests to these APIs (for example, logging the API name and endpoint). I want to have a seperate service for each API (ApiAService, ApiBService, etc), but I don't want to repeat the common logic.
I'd like to do this by creating a core service that each service depends on, but I'm not sure how to do it because the core service would need some configuration that would be specific to each place it's used (for example, the API name).
I know how to do this using traditional composition or inheritance:
Composition
I could make a non-injectable service class that accepts some configuration and instantiate it for each individual API service:
class RequestService(apiName: string) {
public makeRequest(url: string, ...) {...}
}
#Injectable()
class ApiAService {
private readonly requestService = new RequestService("API A")
public queryEndpoint() {
return this.requestService.makeRequest(...)
}
}
Inheritance
I could make the base request service abstract and extend it for each individual API:
#Injectable()
abstract class ApiService {
abstract apiName: string;
protected makeRequest(url: string, ...) {...}
}
#Injectable()
class ApiAService extends ApiService {
private readonly apiName = "API A"
public queryEndpoint() {
return this.makeRequest(...)
}
}
However, I think the most idiomatic Angular way is through dependency injection, and it has the advantage of being able to be swapped out for testing. But if I just add apiName to the injectable core service's constructor, I have no way to actually set the property when depending on it. I don't care if each service has its own instance of RequestService - it doesn't need to be a singleton.
How can I do this?
#Injectable()
class RequestService {
constructor(private apiName: string) {}
public makeRequest(url: string, ...) {...}
}
#Injectable()
class ApiAService {
constructor(private requestService: RequestService) {} // How do I inject apiName here?
public queryEndpoint() {
return this.requestService.makeRequest(...)
}
}
I started developing with angular / typescript and created a service for my .NET Core API and I like to know what's the best way to get a clean and reliable object from my service.
I have an .NET CORE REST API returning a json result represented by the class definition below.
Service:
demoservice.getDemo().subscribe((val) => new Demo(val));
Demo-Class is the following code:
export class Demo {
public id : number;
public name : string;
public subDemo: SubDemo;
constructor(demo: Demo) {
this.id = demo.id;
this.name = demo.name;
this.subDemo = new SubDemo(demo.subDemo);
}
}
export class SubDemo {
public demoList : ListDemo[]
constructor(subDemo: SubDemo) {
this.demoList = new Array<ListDemo>();
subDemo.demoList.forEach(dl => {
this.demoList.push(new ListDemo(dl))
});
}
}
export class ListDemo {
constructor(listdemo : ListDemo) {
this.birthday = listdemo.birthday;
this.smoker = listdemo.smoker;
}
get birthDayFormatted() : Date {
return new Date(this.birthday);
}
public birthday : string;
public smoker : boolean;
}
I this the best way (full implement all constructors) to create a object. Please note I like to use the "getter" - functionality of my ListDemo Class.
Is there no better way? I just found some Object.clone / Object.assign / Object.create.
But none of this solution is comprehensive...
I am really interested in your experience..
Since you're using better & best I will answer with my, probably unwanted, opinion. Disclaimer: I'm no guru, this answer is based on opinion, feel free to disregard.
Don't do it. Your server has a set of objects in its domain, probably some kind of problem solving or data storage domain.
Your client has a set of objects in its domain, typically focused on presenting the data to the user and allowing the user to understand and manipulate it.
Both of these domains may have objects that have the same name or are based on the same real world concept. It can be tempting to feel like they are the same domain with the same objects. They are not. If they were the same you would not be writing a client and a server you would be writing two of the same thing. The two should communicate with pure data objects. In TS this means you should only create an interface, not a class, for the objects you receive from the server.
Instead, start over. Create a new domain based on what you want to appear in the API. If you design your API from the top (UI) down to the bottom (access services) you'll likely find that you don't have a one-to-one mapping between objects. On the occasions you do then you can probably get away with the occasional assign / merge (see below) but I've personally never found reason to do more than what you posted above.
Should you persist you may come across the option to reassign the prototype of the JSON literal from the base object to the class the data represents but that is a contentious topic and potential performance pitfall.. Your best bet is probably to just do a recursive/deep assign like Lodash's merge.
Just use interfaces not classes.
export interface Demo {
id: number;
name: string;
subDemo: SubDemo;
}
export interface SubDemo {
demoList: ListDemo[];
}
export interface ListDemo {
birthday: string;
smoker: boolean;
}
and your api should return the same shape, you should just be able to go
getDemo(): Observable<Demo> {
return this.http.get<Demo>('url');
}
in your service and in your component assign it to a property
demo$ = this.service.getDemo();
and then use the observable with the async pipe in your template.
<ng-container *ngIf="demo$ | async as demo">
{{ demo | json }}
</ng-container>
The less you have to manipulate your data the better. I have a VS pluging that allows you to paste C# classes into TS files and it converts them to TypeScript interfaces on the fly.
I'm trying to get into Nativescript + Angular2, and I read the following in the tutorial:
We’ll build this functionality as an Angular service, which is Angular’s mechanism for reusable classes that operate on data.
What they then do is to create a simple class, like this:
import { Injectable } from "#angular/core";
import { User } from "./user";
#Injectable()
export class UserService {
register(user: User) {
alert("About to register: " + user.email);
}
}
Now, I can't really see the difference between a normal class and a service - this is a very normal class definition.
So, why is it called an "Angular service"?
This creates a basic Angular service with a single method that takes an instance of the User object you created in the previous section.
Also, when using this "service" in the tutorial, it isn't clear to me when this class is instantiated - when is the construction executed? Is the object saved in memory for later use? The only call to the "userservice" in the tutorial is like this:
import { Page } from "ui/page";
import { Component, ElementRef, OnInit, ViewChild } from "#angular/core";
import { User } from "../../shared/user/user";
import { UserService } from "../../shared/user/user.service";
import { Router } from "#angular/router";
import { Color } from "color";
import { View } from "ui/core/view";
#Component({
selector: "my-app",
providers: [UserService],
templateUrl: "./pages/login/login.html",
styleUrls: ["./pages/login/login-common.css", "./pages/login/login.css"]
})
export class LoginComponent implements OnInit {
user: User;
isLoggingIn = true;
#ViewChild("container") container: ElementRef;
constructor(private router: Router, private userService: UserService, private page: Page) {
this.user = new User();
this.user.email = "bla#bla.com";
this.user.password = "1234";
}
//.... methods and stuff...
}
A class, in that context, is a regular class as in any other OO language: a "prototype" of objects which you can create instances simply using:
let myInstance = new MyClass(<arguments...>);
So, actually, an Angular service is also a class.
But consider services a special kind of class. The main difference between regular classes and service classes is their lifecycle, specially who creates their instance (who calls new).
Instances of a service are created - and managed (disposed) - by the Angular "container" (angular injector, actually).
You can also "inject" instances of service classes in constructors of other service classes (or other managed components).
A good resource in the capabilites of services is Angular's Dependency Injection Guide.
When is the construction executed?
The injector executes the construction. When? See below.
Is the object saved in memory for later use?
It could be. Depends on where you registered the service.
Before anything, know that Angular DI is a hierarchical injection system.
If you register the service with an Angular Module, the service will be created by the application's root injector. So everyone below it (aka everyone in that module) will receive the same instance of the service. In other words, Angular (will call the injector only once and) will create only one instance of the service class and pass that same instance to whoever asks for that service. And that instance will live as long as that module lives.
Now, if you register the service with a component, then the service will be registered with that component's injector. So when such component requests an instance of the service, angular will call the injector and create an instance. If any child of that component asks for an instance of such service, angular will provide the same instance. No one else, only children of the component, will receive that same instance. When that component dies, the service instance dies as well.
How does a "regular class" differ? It lacks the Injector?
The difference is not only the lack of an injector.
Angular aside, just JavaScript: you create an instance of a "regular class" by calling let instance = new MyRegularClass() somewhere in your code, right?
This instance has no "magical effects", it does nothing more than any class would (just regular JavaScript methods and properties). Example: if you need instances of other classes as arguments in the constructor, no one will "magically" create you those instances and pass them. You will have to create them manually, when calling new (e.g. new MyClass(new SomeOtherClassIDependOn(), ...)). If you want to instantiate SomeOtherClassIDependOn only once and reuse the same instance everywhere it is needed, you will have to save that instance and pass it wherever it is neeed yourself.
As services, though, angular can take some of that burden off your shoulders.
Now, before anything: since every service, deep down, is a class, someone has to call new MyServiceClass(). The difference is that someone is not you anymore. There is no new UserService() in your code. So, who is it? This someone is the Injector.
When Angular notices someone asks for a service, it calls for the injector to instantiate that service. The injector then calls let serviceInstance = new MyServiceClass(<dependencies>) and adds some "magic" to it (e.g. it can pass - inject - instances of other services to the constructor of a service), and make it available (save it) for anyone that requests that service in the scope you registered it.
Note: You can call new UserService(...) yourself, as it UserService is a class. But this instance is a regular object, not managed by angular, there is no magic (no constructor arguments will be injected, no instance is saved and reused).
I am attempting change the way I am writing AngularJS apps from a plain-javascript to using TypeScript as a pre-processor.
I am struggling to reconcile the two approaches when it comes to scoped method calls.
For illustrative purposes, let's consider the common menu use-case; I wish to highlight a specific menu item which is currently displayed. The HTML template looks like this:
<ul class="nav navbar-nav">
...
<li ng-class="{active: isSelected('/page1')}">Page 1</li>
...
</ul>
This anticipates a scoped function called isSelected. With old-school javascript coding, I' write this as:
$scope.isSelected = function(path) {
return $location.path().substr(0, path.length) == path;
}
This anonymous function declaration doesn't really seem to honor the more traditional class model of TypeScript. In typescript, I find myself tempted to write this:
export interface MenuScope extends ng.IScope {
isSelected(path: String): boolean;
}
export class MenuController {
location: ng.ILocationService;
scope: MenuScope;
constructor($scope: MenuScope, $location: ng.ILocationService) {
this.scope = $scope;
this.location = $location;
this.scope.isSelected = function(path) { return this.isSelected(path) }.bind(this);
}
isSelected(path: String): boolean {
return this.location.path().substr(0, path.length) == path;
}
}
In this case, isSelected belongs to the controller, rather than the scope. This seems sensible. However, the "link" between the scope and controller still relies on an anonymous method.
Even worse, I've had to explicitly bind the context of this to ensure I can write this.location to access the location service in the implementation of isSelected().
One of the benefits I am looking for from TypeScript is a clearer way of writing code. This indirection through a binded anonymous function seems to be the antithesis of this.
You shouldn't store your $scope as a variable in this but instead use this as the $scope, the way to do this is to do $scope.vm = this; in the beginning of the constructor, now every function and variable of the class will be part of the $scope.
You can't avoid this.location = $location because this is the syntax of TypeScript.
BTW you should use $inject for the dependencies.
Here is a simple app with a controller and a service. I use this style in my projects:
/// <reference path="typings/angularjs/angular.d.ts" />
module App {
var app = angular.module("app", []);
app.controller("MainController as vm", Controllers.MainController);
app.service("backend", Services.Backend);
}
module App.Controllers {
export class MainController {
public persons: Models.Person[];
static $inject = ["$location", "backend"];
constructor(private $location: ng.ILocationService, private backend: Services.Backend) {
this.getAllPersons();
}
public isSelected(path: string): boolean {
return this.$location.path().substr(0, path.length) == path;
}
public getAllPersons() {
this.backend.getAllPersons()
.then((persons) => {
this.persons = persons;
})
.catch((reason) => console.log(reason));
}
}
}
module App.Services {
export class Backend {
static $inject = ["$http"];
constructor(private $http: ng.IHttpService) { }
public getAllPersons(): ng.IPromise<Models.Person[]> {
return this.$http.get("api/person")
.then((response) => response.data);
}
}
}
module App.Models {
export interface Person {
id: number;
firstName: string;
lastName: string;
}
}
I have modules of app, controllers, services and models.
controller defined as a class but must be registered to app through controller as syntax. So everything you define in class is accessible through vm in the view (controller scope). Here we have persons, isSelected and getAllPersons.
You can inject every injectable through static $inject that is a string[], then add them as constructor parameters respectively. This role is also usable when defining services and it is minifiable.
You can also inject $scope to your controller class to access scope specific tools such as $apply, on etc.
Instead of defining factories you can define services to be able to define them as a class.
Injecting in services is the same as injecting in controllers.
You can define return type of you http calls as ng.IPromise<Model> then return response.data to ensure that type of your return method is just entities, not http related data.
We were considering a similar conversion (e.g. from Javascript to Typescript for Angular). There were certain things (like your example) that looked very odd as we started to implement. The quickest way to go from what you have is to use the controller as syntax. This way, you expose methods directly on the controller.
<!-- use controller as syntax -->
<div ng-controller="MenuController as menu">
<ul class="nav navbar-nav">
...
<li ng-class="{active: menu.isSelected('/page1')}">Page 1</li>
...
</ul>
</div>
This would allow you to get past the need to bind the scope's method back to that on the controller. Things I don't like about this approach:
Each injectable (e.g. $scope, $location) is now available directly through the controller. This might not be a big deal, but seems undesirable when you want to know exactly what the controller can do and keeping things properly scoped.
The generated code of classes seems overly cluttered and not optimized for minification... This is more of a pet peeve of mine where you trade the ease of using something familiar like class for code that still has room for optimization. See generated code for Inheritance at the Typescript Playground (extends function generated for each .js file where you want to extend a class unless you have your references are on point, the prototype of the function could be cached to add methods to it instead of ClassName.prototype.method for each and every method...), but I digress
The other option is to not use classes, but to stick to strongly typed functions:
export function MenuController($scope: MenuScope, $location: ng.ILocationService): any {
$scope.isSelected = function(path:string): boolean {
return $location.path().substr(0, path.length) == path;
}
}
Since angular is responsible for instantiating the controller, the return type any doesn't matter. But you could get caught if you had a typo on your $scope's method.
To get around this, you can go a step further by using controller as syntax. The example below won't let you actually new up your controller yourself (e.g. new MenuController($location) would fail with only void function can be called with new keyword), but this is negligible since angular handles the instantiation for you.
export interface IMenuController {
isSelected(path: string): boolean;
}
export function MenuController($location: ng.ILocationService): IMenuController {
var self:IMenuController = this;
self.isSelected = function(path:string): boolean {
return $location.path().substr(0, path.length) == path;
}
// explicitly return self / this to compile
return self;
}
TL DR: I'm a fan of the compile time checking of types, and would love to use the concept of class. However, I don't think it completely fits with the Angular 1.x model. It seems like this is designed to work for Angular2. Use strongly typed functions instead for Angular 1.x.