Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store/deal with data available to other classes in c#

Tags:

c#

class

static

I'm writing a CAD program. Let's say I have in input class, this class reads various data from a text file and creates lots of lists/dictionaries and .... These data need to be accessed by other methods in other classes to be modified. Now here is how I have done it so far:

I have one static class: Building.cs When I create/or load a project this class holds all the data like list of columns, beams, points, etc. All of these are stored as private fields. I can access these using the class's public methods like GetColumns or GetPoints ...

Now I also have non-static classes. They contain 2-3 public methods. and do some stuff on various parts of the building.

public static class Building
{
    private static List<Column> columns;
    private static List<Beams> beams;
    private static List<Points> points;

    public static List<Column> GetColumns() 
    {
        return Columns;
    }
}

public class ColumnsService()
{
    private List<Columns> columns;
    public GroupColumns(List<Columns> columns)
    {
        this.columns = columns;
    }

    public void Group()
    {
        // group columns
    }
}

var columns = Building.GetColumns();
var columnsService = new ColumnsService(columns);
columnsService.Group();

I was wondering is this the way to go? How else can I store the data. The data needs to be accessible throughout the lifetime of the program to most of the classes. What are the best practices.

like image 600
Vahid Avatar asked Mar 18 '23 14:03

Vahid


1 Answers

What, semantically, is a Building?

To me, the name implies that it's an instance of a structure. That, in the overall business domain, there can be many "buildings" and at any given moment one is interacting with one of them.

If that's the case, then it seems unintuitive to me to make it static. If there's more than one, it should be an instance model. It would contain attributes which describe it and operations which interact with it. The business domain being modeled should drive the structure of this object before any consideration is given to how other objects are going to interact with it.

So let's assume we make it an instance model:

public class Building
{
    // attributes and operations
}

Then, as you ask, how do other objects interact with it?

Depends on the interactions.

Let's say an object needs to "render" a building in some way. Let's call it BuildingPrinter for lack of a better term. Clearly it needs a Building to "print". So it requires one for that operation:

public class BuildingPrinter
{
    public void Print(Building building)
    {
        // implementation
    }
}

Or perhaps you have an object which "wraps" a building in some way. Something which can't meaningfully exist without a building, regardless of the operations performed. I can't think of one for that particular business domain, so let's just call it a BuildingWidget. Since it needs a building to exist at all, it requires one:

public class BuildingWidget
{
    private Building currentBuilding;

    private BuildingWidget() { }

    public BuildingWidget(Building building)
    {
        currentBuilding = building;
    }
}

The point is, from the perspective of the models which construct the overall domain, if something is required then it must be supplied. The models shouldn't go out to some global data store, tightly coupling with that data store, to get what they need. This is called the Dependency Inversion Principle.

But where will the consuming code which orchestrates the interactions of these models get instances of a Building? There are a number of potential solutions to that.

Two common patterns would be to have a static factory or a repository. For example:

public class BuildingFactory
{
    public static Building FetchBuilding(int buildingId)
    {
        // implementation
    }
}

This factory might have a static cached building object. The building itself isn't static, but for performance reasons an instance of it is cached statically so that it's not constantly re-fetched from a backing data store (such as a database). You might also add methods to invalidate the cache and re-fetch, or encapsulate that logic into the factory itself (such as always re-fetch after 5 minutes or after 10 accesses or some other rule). (Behind the scenes, this factory might even use a repository, shown below, to re-fetch that instance. In which case, you guessed it, a BuildingRepository would be required on the BuildingFactory constructor.)

This factory object may also be responsible for creating a building based on some specifications, if for example you have reason to make the Building constructor private.

Or, to re-fetch from data, consider a repository:

public class BuildingRepository
{
    public Building GetBuilding(int buildingId)
    {
        // fetch from database
    }

    public Building SaveBuilding(Building building)
    {
        // save to database, return updated version
    }
}

Then other code throughout the domain, including the consuming code, can use these objects to get/save buildings. The factory is static, so that can be invoked anywhere. The repository is instance but doesn't need to be globally distinct, so that can be instantiated anywhere (or pulled form a dependency injection container).

like image 116
David Avatar answered Mar 31 '23 22:03

David