You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
6.7 KiB
178 lines
6.7 KiB
![]()
2 years ago
|
---
|
||
|
sidebar_position: 7
|
||
|
title: Use the Pattern Factory
|
||
|
---
|
||
|
|
||
|
In the code of the `Edit.razor.cs` page, we have transformed our item into the model and vice versa.
|
||
|
|
||
|
We currently use this code only in two pages, if we added a new field, it would be necessary to pass on each page in order to carry out the modifications of assignment.
|
||
|
|
||
|
We are therefore going to use the Factory pattern.
|
||
|
|
||
|
## Creation of our factory
|
||
|
|
||
|
To do this, create the `Factories` folder at the root of the site.
|
||
|
|
||
|
In this folder create a new `ItemFactory` class and modify it as follows:
|
||
|
|
||
|
```csharp title="Factories/ItemFactory.cs"
|
||
|
public static class ItemFactory
|
||
|
{
|
||
|
public static ItemModel ToModel(Item item, byte[] imageContent)
|
||
|
{
|
||
|
return new ItemModel
|
||
|
{
|
||
|
Id = item.Id,
|
||
|
DisplayName = item.DisplayName,
|
||
|
Name = item.Name,
|
||
|
RepairWith = item.RepairWith,
|
||
|
EnchantCategories = item.EnchantCategories,
|
||
|
MaxDurability = item.MaxDurability,
|
||
|
StackSize = item.StackSize,
|
||
|
ImageContent = imageContent
|
||
|
};
|
||
|
}
|
||
|
|
||
|
public static Item Create(ItemModel model)
|
||
|
{
|
||
|
return new Item
|
||
|
{
|
||
|
Id = model.Id,
|
||
|
DisplayName = model.DisplayName,
|
||
|
Name = model.Name,
|
||
|
RepairWith = model.RepairWith,
|
||
|
EnchantCategories = model.EnchantCategories,
|
||
|
MaxDurability = model.MaxDurability,
|
||
|
StackSize = model.StackSize,
|
||
|
CreatedDate = DateTime.Now
|
||
|
};
|
||
|
}
|
||
|
|
||
|
public static void Update(Item item, ItemModel model)
|
||
|
{
|
||
|
item.DisplayName = model.DisplayName;
|
||
|
item.Name = model.Name;
|
||
|
item.RepairWith = model.RepairWith;
|
||
|
item.EnchantCategories = model.EnchantCategories;
|
||
|
item.MaxDurability = model.MaxDurability;
|
||
|
item.StackSize = model.StackSize;
|
||
|
item.UpdatedDate = DateTime.Now;
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
A factory is always `static` ie it never instantiates, it can be considered as a converter.
|
||
|
|
||
|
## Using our factory
|
||
|
|
||
|
Open the `Services/DataLocalService.cs` file and modify as follows:
|
||
|
|
||
|
```csharp title="Services/DataLocalService.cs"
|
||
|
...
|
||
|
|
||
|
public async Task Add(ItemModel model)
|
||
|
{
|
||
|
...
|
||
|
|
||
|
// Simulate the Id
|
||
|
model.Id = currentData.Max(s => s.Id) + 1;
|
||
|
|
||
|
// Add the item to the current data
|
||
|
// highlight-next-line
|
||
|
currentData.Add(ItemFactory.Create(model));
|
||
|
|
||
|
// Save the image
|
||
|
var imagePathInfo = new DirectoryInfo($"{_webHostEnvironment.WebRootPath}/images");
|
||
|
|
||
|
...
|
||
|
}
|
||
|
|
||
|
public async Task Update(int id, ItemModel model)
|
||
|
{
|
||
|
...
|
||
|
|
||
|
// Write the file content
|
||
|
await File.WriteAllBytesAsync(fileName.FullName, model.ImageContent);
|
||
|
|
||
|
// Modify the content of the item
|
||
|
// highlight-next-line
|
||
|
ItemFactory.Update(item, model);
|
||
|
|
||
|
// Save the data
|
||
|
await _localStorage.SetItemAsync("data", currentData);
|
||
|
}
|
||
|
|
||
|
...
|
||
|
```
|
||
|
|
||
|
```csharp title="Pages/Edit.razor.cs"
|
||
|
...
|
||
|
|
||
|
protected override async Task OnInitializedAsync()
|
||
|
{
|
||
|
var item = await DataService.GetById(Id);
|
||
|
|
||
|
var fileContent = await File.ReadAllBytesAsync($"{WebHostEnvironment.WebRootPath}/images/default.png");
|
||
|
|
||
|
if (File.Exists($"{WebHostEnvironment.WebRootPath}/images/{itemModel.Name}.png"))
|
||
|
{
|
||
|
fileContent = await File.ReadAllBytesAsync($"{WebHostEnvironment.WebRootPath}/images/{item.Name}.png");
|
||
|
}
|
||
|
|
||
|
// Set the model with the item
|
||
|
// highlight-next-line
|
||
|
itemModel = ItemFactory.ToModel(item, fileContent);
|
||
|
}
|
||
|
|
||
|
...
|
||
|
```
|
||
|
|
||
|
## Concept: Factory Pattern
|
||
|
|
||
|
### What is the factory pattern?
|
||
|
|
||
|
The factory pattern describes a programming approach that allows you to create objects without having to specify the exact class of those objects.
|
||
|
This makes exchanging the created item flexible and convenient.
|
||
|
For the implementation, developers use the factory design pattern, also called factory pattern, which gives its name to the model.
|
||
|
This method is either specified in an interface and implemented by a child class, or implemented by a base class and possibly overridden (by derived classes).
|
||
|
The pattern thus replaces the usual class constructor to detach the creation of objects from the objects themselves, thus making it possible to follow the so-called SOLID principles.
|
||
|
|
||
|
:::tip
|
||
|
|
||
|
**SOLID Principles** are a subset of object-oriented programming (OOP) principles that aim to improve the object-oriented software development process. The acronym "SOLID" refers to the following five principles:
|
||
|
|
||
|
- Principle of **S**ingle-Responsibility: each class should have only one responsibility.
|
||
|
|
||
|
- Principle of **O**pen-Closed: the software units must be able to be extended without having to modify their behavior.
|
||
|
|
||
|
- Principle of **L**iskov Substitutions: a derived class must always be usable instead of its base class.
|
||
|
|
||
|
- Principle of **I**nterface-Segregation: the interfaces must be perfectly adapted to the needs of the customers who access them.
|
||
|
|
||
|
- Principle of **D**ependency-Inversion: classes at a higher level of abstraction should never depend on classes at a lower level of abstraction.
|
||
|
|
||
|
:::
|
||
|
|
||
|
### What is the purpose of the factory pattern?
|
||
|
|
||
|
The factory pattern aims to solve a fundamental problem during instantiation, i.e. the creation of a concrete object of a class, in object-oriented programming:
|
||
|
**creating an object directly within the class**, which needs this object or should use it, is possible in principle, but **very rigid**.
|
||
|
It binds the class to that particular object and makes it impossible to modify the instantiation independent of the class.
|
||
|
The factory pattern avoids such code by first defining a separate operation for creating the object: the factory.
|
||
|
When called, it generates the object, instead of the class constructor mentioned above.
|
||
|
|
||
|
### The pros and cons of the factory pattern
|
||
|
|
||
|
In the factory pattern, calling a program method is completely separate from implementing new classes, which has some advantages.
|
||
|
This has an effect in particular on the **extensibility of software**: instances of the factory pattern have a high degree of autonomy and allow you to **add new classes** without the application having to change in any way, alongside execution.
|
||
|
Just implement the factory interface and instantiate the creator accordingly.
|
||
|
|
||
|
Another advantage is the good testability of the factory components.
|
||
|
If a `factory` implements three classes, for example, their functionality can be tested individually and independently of the calling class.
|
||
|
In the case of the latter, you just need to make sure that it calls the `factory` correctly, even if the software is extended to this step later.
|
||
|
The ability to give a meaningful name to the factory pattern (as opposed to a class constructor) is also beneficial.
|
||
|
|
||
|
The great weakness of the factory pattern is the fact that its implementation leads to a large increase in the classes included.
|
||
|
As cost-effective as the factory pattern approach is in principle when it comes to extending software, it is also disadvantageous when it comes to effort:
|
||
|
if a product family is to be extended, not only the interface, but also all subordinate classes of the `factory` must be adapted accordingly.
|
||
|
Good advance planning of the types of products required is therefore essential.
|