In the book The object oriented thought process it is stated that:
Encapsulation is the process of packaging classes into the public
interface and the private implementation.
Example:
---------------------------
| Cabbie |
---------------------------
| -companyName: String |
---------------------------
| -name: String |
---------------------------
| +Cabbie: void |
| +Cabbie: void |
| +setName: void |
| +getName: String |
| +giveDirections: void |
| -turnRight: void |
| -turnLeft: void |
| +getCompanyName: String |
---------------------------
---------------------------
| PartTimeCabbie |
---------------------------
| partTimeHours: int |
---------------------------
| +setPartTimeHours: void |
| +getPartTimeHours: int |
---------------------------
PartTimeCabbie is a subclass of Cabbie. Thus, PartTimeCabbie inherits
the public implementation of Cabbie, including the method
giveDirections(). If the method giveDirections()is changed in Cabbie,
it will have a direct impact on PartTimeCabbie and any other classes
that might later be subclasses of Cabbie. In this subtle way, changes
to the implementation of Cabbie are not necessarily encapsulated
within the Cabbie class.
I don't uderstand the concept of public implementation? Is it not a private implementation and public interface?
Related
I used command below to create a ProductsController (Note: I'm new to Laravel and PHP)
php artisan make:controller ProductsController --model=Product
I see that it created a controller with an index() function like below:
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
//
}
What would be the best way to give it the ability to show products by category? My thought is to make a route like this:
/products/{category}. So, I created a Category Enum and added that as the parameter of the index function (see below). But it does not work. Because when I entered an url like this http://localhost:8000/admin/products/Parts, it does not hit the /products/{category} route. Instead, it is hitting the "products/{product} ......... products.show" route.
// create a Category ENUM
namespace App\Enums;
enum Category: string
{
case Parts = 'Parts';
case Vehicles = 'Vehicles';
case All = 'All';
}
// Change the index method in the ProductsController to be like below
public function index(Category $category)
{
return $category->value;
}
// below is how I define the routes
Route::resource('products', ProductsController::class);
Since a product belongs to a particular category, you should instead define your route as:
Route::resource('categories.products', ProductsController::class);
That would generate the routes below:
$ php artisan route:list | grep "categories.products"
| | GET|HEAD | categories/{category}/products | categories.products.index | App\Http\Controllers\ProductsController#index | web |
| | POST | categories/{category}/products | categories.products.store | App\Http\Controllers\ProductsController#store | web |
| | GET|HEAD | categories/{category}/products/create | categories.products.create | App\Http\Controllers\ProductsController#create | web |
| | GET|HEAD | categories/{category}/products/{product} | categories.products.show | App\Http\Controllers\ProductsController#show | web |
| | PUT|PATCH | categories/{category}/products/{product} | categories.products.update | App\Http\Controllers\ProductsController#update | web |
| | DELETE | categories/{category}/products/{product} | categories.products.destroy | App\Http\Controllers\ProductsController#destroy | web |
| | GET|HEAD | categories/{category}/products/{product}/edit | categories.products.edit | App\Http\Controllers\ProductsController#edit | web |
In your frontend source code, you could use this URL path:
http://localhost:8000/admin/categories/Parts/products
We have a problem with SignalR, which we currently cannot fully understand:
System
Framework: .NET Core 2.2
Entity Framework: 2.2.6.0
Description of the problem
We use SignalR to communicate with multiple clients. Via the connection the clients log on to the server with a unique key. We use the Entity Framework to access the database and select the client for the given key. Now it has happened for the second time that the wrong client entry was selected for the key during the access and therefore a wrong login with the wrong client has made. This happened when
about 8 clients have logged on via the hub at the same time.
We assume that there are problems with the DbContext because it is not Threadsafe and for some reason the same Context is accessed for multiple requests(maybe this can be solved by updating to Core 3.1). However, we would like to understand how this can happen or why it failes. How does it happen that accessing the DbContext via FirstOrDefaultAsync() returns the wrong client? The Hub and the DbContext should be instantiated per request?
Example
The database currently contains several client entries:
+------------+---------+
| ClientId | Key |
+------------+---------+
| 1 | ABC |
| 2 | DEF |
| 3 | GHI |
| ... | ... |
+------------+---------+
Now several clients log in with their key at the same time. In one of the cases the wrong client was returned:
Key ABC returns Client 1
Key DEF returns Client 2
Key GHI returns Client 1
Structure
Our server provides a SignalR-Hub, which is configured in the Startup:
app.UseSignalR(routes =>
{
routes.MapHub<MyServerHub>("/myhub");
});
According to the documentation and source code, the hub should be registered as transient (Use hubs in SignalR for ASP.NET Core).
We also use a service in the hub, which is injected by DI.
public MyServerHub(IMyDatabaseService myDatabaseService)
{
_myDatabaseService = myDatabaseService;
}
This service uses the DbContext:
private MyContext _myContext { get; }
public MyDatabaseService(MyContext myContext)
{
_myContext= myContext;
}
In the Startup the service and the DbContext is defined as Scoped:
services.AddScoped<IMyDatabaseService, MyDatabaseService>();
services.AddDbContext<MyContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
In this method of hub we get the wrong client for a key:
public async Task Connect(string key)
{
if (!string.IsNullOrWhiteSpace(key))
{
var client = await _myDatabaseService.GetByKey(key);
if(client == null)
{
await LogInformation(key, null, ConnectionEvent.ConnectWithInvalidKey);
await Clients.Caller.ReceiveInvalidKey();
return;
}
await Clients.Caller.ReceiveValidClientKey(client.Id);
// This created following logs:
// "ABC" with id "1" at 09:25:47
// "GHI" with id "3" at 09:34:03
// "GHI" with id "1" at 10:06:02
// "ABC" with id "1" at 10:06:03
await LogInformation(key, client.Id, ConnectionEvent.ConnectedSuccessfully);
}
else
await Clients.Caller.ReceiveInvalidKey();
}
Access to the DbContext in MyDatabaseService:
public async Task<Client> GetByKey(string key)
{
ClientRecord client = await _myContext.Clients.FirstOrDefaultAsync(p => p.Key == key);
if (client == null)
return null;
return new Client
{
Id = client.Id,
Key = client.Key
};
}
EDIT: Logging Informations
We log every call on the server hub. At 10:06:01 all connected SignalR clients (~18) were disconnected by with unkown reason (OnDisconnectedAsync was executed for each client). From 10:06:02 to 10:06:03 the clients automatically reconnected via our client application.
+------------+---------+-----------------------+---------------------+----------+
| ClientId | Key | ConnectionId | Event | Date |
+------------+---------+-----------------------+---------------------+----------+
| - | - |jF2OqBVgBb1PLOiVRn8SPQ | SignalR-Connected | 9:25:47 |
| 1 | ABC |jF2OqBVgBb1PLOiVRn8SPQ | Connected | 9:25:47 |
| ... | ... |... | ... | ... |
| - | - |5fg1CwmZxFjGXF42zb-7BQ | SignalR-Connected | 9:34:02 |
| 3 | GHI |5fg1CwmZxFjGXF42zb-7BQ | Connected | 9:34:03 |
| ... | ... |... | ... | ... |
| 1 | - |jF2OqBVgBb1PLOiVRn8SPQ | SignalR-Disconnected| 10:06:01 |
| 3 | - |5fg1CwmZxFjGXF42zb-7BQ | SignalR-Disconnected| 10:06:01 |
| ... | ... |... | ... | ... |
| - | - |2lZfpu08UerqbjwNkKLC3Q | SignalR-Connected | 10:06:02 |
| - | - |fg0oXdDAoKW3D4Ps6WOhhg | SignalR-Connected | 10:06:02 |
| 1 | GHI |fg0oXdDAoKW3D4Ps6WOhhg | Connected | 10:06:02 |
| 1 | ABC |2lZfpu08UerqbjwNkKLC3Q | Connected | 10:06:03 |
+------------+---------+-----------------------+---------------------+----------+
I am having a table to store individual pages of courses. The table looks like :
Pages :
---------------------------------------------------
CourseId | LessonId | TopicId | Url
---------------------------------------------------
1 | 1 | 0 | lesson-1
---------------------------------------------------
1 | 1 | 1 | lesson-1-Topic-1
---------------------------------------------------
1 | 1 | 2 | lesson-1-Topic-2
---------------------------------------------------
1 | 1 | 3 | lesson-1-Topic-3
---------------------------------------------------
1 | 2 | 0 | lesson-2
---------------------------------------------------
1 | 2 | 1 | lesson-2-Topic-1
---------------------------------------------------
1 | 2 | 2 | lesson-2-Topic-2
---------------------------------------------------
The CourseId, LessonId & TopicId are integers and constitute the Primary Key for the table. This model enables me to quickly know the lesson, the topic serial no. , topics in a lesson.
I wish to have entity model like :
Public class Page
{
public int CourseId {get;set;}
public int LessonId {get;set;}
public int TopicId {get;set;}
// Need to write custom logic to fetch and set below properties
// Whenever this entity is initialized
public Page PreviousPage {get;set;}
public Page NextPage {get;set;}
public Page LessonPage {get;set;}
public ICollection<Page> ChildPages {get;set;}
}
How can i set these custom properties within the model ? We can query the DB in the controller and set these properties. Wouldn't that push the application logic in the controller ?
Platform / libraries : Asp.Net Core 2.0, MySQL 5.7, Pomelo.EntityFrameworkCore.Mysql
I have create a couple of Scenarios in fitnesse using Xebium/Selenium. They works nice but I'd like to create a decision table from one of my scenario.
So I try with the following:
| Verifiera ärendet | selenium driver fixture |
| tabellRadsNr | längd | bredd | grisar | höns | getter | får | kod | felbeskrivning |
| 19 | 50 | 20 | 201 | 0 | 0 | 0 | R110 | Nekad |
And ends up with:
Could not invoke constructor for VerifieraÄrendet[1]
The instance decisionTable_25. does not exist
The scenario "Verifiera ärendet" works when I run it by itself so I guess that I am missing something....
The problem was that I mixed up parameter names and their value names. So the structure basically is
| scenarioname parametername2 |
| parametervaluename1 | parametervaluename2 |
| row1value1 | row1value2 |
| row2value1 | row2value2 |
I have two classes, and the methods in them are shown below;
|----AVL----| |-----RB------|
| | | |
| | | |
| - insert | | -balance |
| | | |
| - balance | | |
| | | |
|-----------| |-------------|
inside "insert" method of AVL, it calls "balance".
RB inherits AVL, so I can use insert method of AVL. Now when I call RB::insert(), it calls AVL::insert() & then AVL::balance(), but I want it to call RB::balance() from AVL::insert(), when a RB object calls "insert".
This is a classic case for virtual methods: make AVL.balance virtual and override it in RB. The correct implementation will then be called depending on what type of object calls balance -- it doesn't matter that the code that calls balance will be written as part of AVL.