Is adding this hierarchically class an antipattern - oop

I had some classes like this:
+---+ +---+
| L | ---uses---> | D |
+---+ +---+
| +---+
inherit ----<---- | V |
| +---+ +---+
+---<--- | C |
+---+
Let's say; class L is an abstract class, and V and C inherits from it. And L have a property of class D. - sorry for my bad drawing and also English-
Now, I need to add a new class -RA- that has a property of class D and class V should have a property of class RA, But I also need to get property from objects of class L So V. In my mind something like this:
+---+ +---+ +----+
| L | --uses--> | D | <--uses-- | RA |
+---+ +---+ +----+
| +---+ |
inherit ----<----| V | --uses-->--+
| +---+ +---+
+---<---| C |
+---+
I'm not sure!; But it seems to me like an anti-pattern or breaker of LSP -of SOLID principle- somehow!, But I can't figure it out.
Is my new diagram an anti-pattern? or is there a better way to design this situation?
Note that classes like D, V, C and RA can instantiate.
And I meant that usage of property of class D is now hierarchically in class V.
Edit:
Imagine that I use an interface -IGFP- that returned a string value by using D property in L so in V and C, now in V I need to override it by using RA instead of D.
In C# classes are:
public abstract class L : VOBase<L>, IGFP {
public virtual D D { get; protected set; }
public virtual string Name { get; protected set; }
public virtual string GFP => $"{D.GFP}/{Name}"; // Here I use D property that I think breaks LSP
}
public class C : L {
public C (D d, string name) {
D = d;
Name = name;
}
}
public class V : L {
public V (RA ra, string name) {
RA = ra;
Name = name;
D = ra.D;
}
public RA RA { get; private set; }
public override string GFP => $"{RA.GFP}/{Name}"; // Here I should override GFP to use RA instead of D
}
public class D : VOBase<D>, IGFP {
public D (U u, string name) {
U = u;
Name = name;
}
public U U { get; private set; }
public string Name { get; private set; }
public string GFP => $"{U.GFP}/{Name}";
}
public class RA : VOBase<RA>, IGFP {
public RA (D d, string name) {
D = d;
Name = name;
}
public D D { get; private set; }
public string Name { get; private set; }
public string GFP => $"{D.GFP}/{Name}";
}

I'm sure whatever you are smelling isn't really described by this question.
But let me attempt to break it down.
First D is only used by two other classes. Nothing wrong with that. What makes D any different from both classes referencing a class like String? So let's remove it from the diagram:
+---+ +----+
| L | | RA |
+---+ +----+
| +---+ |
inherit ----<----| V | --uses-->--+
| +---+ +---+
+---<---| C |
+---+
Now, RA is only used, why is that any different from using a class like String or D, let's remove it from the diagram:
+---+
| L |
+---+
| +---+
inherit ----<----| V |
| +---+ +---+
+---<---| C |
+---+
So now we have a very simple diagram that doesn't demonstrate any issues.
So, no, your diagram doesn't indicate any anti pattern. But that's not to say it's not one, just that the diagram doesn't contain enough information. I know you have tried to explain in English, but English is ambiguous. Only seeing an actual code example of how these classes interact would allow people to identify anti-patterns or improvements.

Related

RavenDB: How can I properly index a cartesian product in a map-reduce?

This question is a spin-off of RavenDB: Why do I get null-values for fields in this multi-map/reduce index?, but I realized, the problem was another.
Consider my extremely simplified domain, rewritten to a movie rental store scenario for abstraction:
public class User
{
public string Id { get; set; }
}
public class Movie
{
public string Id { get; set; }
}
public class MovieRental
{
public string Id { get; set; }
public string MovieId { get; set; }
public string UserId { get; set; }
}
It's a text-book many-to-many example.
The index I want to create is this:
For a given user, give me a list of every movie in the database (filtering/search left out for the moment) along with an integer describing how many times (or zero) the user has rented this movie.
Basically like this:
Users:
| Id |
|--------|
| John |
| Lizzie |
| Albert |
Movies:
| Id |
|--------------|
| Robocop |
| Notting Hill |
| Inception |
MovieRentals:
| Id | UserId | MovieId |
|-----------|--------|--------------|
| rental-00 | John | Robocop |
| rental-01 | John | Notting Hill |
| rental-02 | John | Notting Hill |
| rental-03 | Lizzie | Robocop |
| rental-04 | Lizzie | Robocop |
| rental-05 | Lizzie | Inception |
Ideally, I want an index to query, that would look like this:
| UserId | MovieId | RentalCount |
|--------|--------------|-------------|
| John | Robocop | 1 |
| John | Notting Hill | 2 |
| John | Inception | 0 |
| Lizzie | Robocop | 2 |
| Lizzie | Notting Hill | 0 |
| Lizzie | Inception | 1 |
| Albert | Robocop | 0 |
| Albert | Notting Hill | 0 |
| Albert | Inception | 0 |
Or declaratively:
I always want a full list of all the movies (eventually I will add filtering/searching) - even when providing a user that has never rented a single movie yet
I want a count of the rentals for each user, just the integer
I want to be able to sort by the rental-count - i.e. show the most-rented movies for a given user at the top of the list
However, I can't find a way to make the "cross-join" above and save it in the index. Instead, I initially thought I got it right with this maneuver below, but it does not allow me to sort (see failing test):
{"Not supported computation: x.UserRentalCounts.SingleOrDefault(rentalCount => (rentalCount.UserId == value(UnitTestProject2.MovieRentalTests+<>c__DisplayClass0_0).user_john.Id)).Count. You cannot use computation in RavenDB queries (only simple member expressions are allowed)."}
My question is basically: how can I - or can I at all - index so, that my requirements are fulfilled?
Below is my mentioned example, that does not fulfill my requirements, but that's where I am right now. It uses the following packages (VS2015):
packages.config
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Owin.Host.HttpListener" version="3.0.1" targetFramework="net461" />
<package id="NUnit" version="3.5.0" targetFramework="net461" />
<package id="RavenDB.Client" version="3.5.2" targetFramework="net461" />
<package id="RavenDB.Database" version="3.5.2" targetFramework="net461" />
<package id="RavenDB.Tests.Helpers" version="3.5.2" targetFramework="net461" />
</packages>
MovieRentalTests.cs
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Raven.Client.Indexes;
using Raven.Client.Linq;
using Raven.Tests.Helpers;
namespace UnitTestProject2
{
[TestFixture]
public class MovieRentalTests : RavenTestBase
{
[Test]
public void DoSomeTests()
{
using (var server = GetNewServer())
using (var store = NewRemoteDocumentStore(ravenDbServer: server))
{
//Test-data
var user_john = new User { Id = "John" };
var user_lizzie = new User { Id = "Lizzie" };
var user_albert = new User { Id = "Albert" };
var movie_robocop = new Movie { Id = "Robocop" };
var movie_nottingHill = new Movie { Id = "Notting Hill" };
var movie_inception = new Movie { Id = "Inception" };
var rentals = new List<MovieRental>
{
new MovieRental {Id = "rental-00", UserId = user_john.Id, MovieId = movie_robocop.Id},
new MovieRental {Id = "rental-01", UserId = user_john.Id, MovieId = movie_nottingHill.Id},
new MovieRental {Id = "rental-02", UserId = user_john.Id, MovieId = movie_nottingHill.Id},
new MovieRental {Id = "rental-03", UserId = user_lizzie.Id, MovieId = movie_robocop.Id},
new MovieRental {Id = "rental-04", UserId = user_lizzie.Id, MovieId = movie_robocop.Id},
new MovieRental {Id = "rental-05", UserId = user_lizzie.Id, MovieId = movie_inception.Id}
};
//Init index
new Movies_WithRentalsByUsersCount().Execute(store);
//Insert test-data in db
using (var session = store.OpenSession())
{
session.Store(user_john);
session.Store(user_lizzie);
session.Store(user_albert);
session.Store(movie_robocop);
session.Store(movie_nottingHill);
session.Store(movie_inception);
foreach (var rental in rentals)
{
session.Store(rental);
}
session.SaveChanges();
WaitForAllRequestsToComplete(server);
WaitForIndexing(store);
}
//Test of correct rental-counts for users
using (var session = store.OpenSession())
{
var allMoviesWithRentalCounts =
session.Query<Movies_WithRentalsByUsersCount.ReducedResult, Movies_WithRentalsByUsersCount>()
.ToList();
var robocopWithRentalsCounts = allMoviesWithRentalCounts.Single(m => m.MovieId == movie_robocop.Id);
Assert.AreEqual(1, robocopWithRentalsCounts.UserRentalCounts.FirstOrDefault(x => x.UserId == user_john.Id)?.Count ?? 0);
Assert.AreEqual(2, robocopWithRentalsCounts.UserRentalCounts.FirstOrDefault(x => x.UserId == user_lizzie.Id)?.Count ?? 0);
Assert.AreEqual(0, robocopWithRentalsCounts.UserRentalCounts.FirstOrDefault(x => x.UserId == user_albert.Id)?.Count ?? 0);
var nottingHillWithRentalsCounts = allMoviesWithRentalCounts.Single(m => m.MovieId == movie_nottingHill.Id);
Assert.AreEqual(2, nottingHillWithRentalsCounts.UserRentalCounts.FirstOrDefault(x => x.UserId == user_john.Id)?.Count ?? 0);
Assert.AreEqual(0, nottingHillWithRentalsCounts.UserRentalCounts.FirstOrDefault(x => x.UserId == user_lizzie.Id)?.Count ?? 0);
Assert.AreEqual(0, nottingHillWithRentalsCounts.UserRentalCounts.FirstOrDefault(x => x.UserId == user_albert.Id)?.Count ?? 0);
}
// Test that you for a given user can sort the movies by view-count
using (var session = store.OpenSession())
{
var allMoviesWithRentalCounts =
session.Query<Movies_WithRentalsByUsersCount.ReducedResult, Movies_WithRentalsByUsersCount>()
.OrderByDescending(x => x.UserRentalCounts.SingleOrDefault(rentalCount => rentalCount.UserId == user_john.Id).Count)
.ToList();
Assert.AreEqual(movie_nottingHill.Id, allMoviesWithRentalCounts[0].MovieId);
Assert.AreEqual(movie_robocop.Id, allMoviesWithRentalCounts[1].MovieId);
Assert.AreEqual(movie_inception.Id, allMoviesWithRentalCounts[2].MovieId);
}
}
}
public class Movies_WithRentalsByUsersCount :
AbstractMultiMapIndexCreationTask<Movies_WithRentalsByUsersCount.ReducedResult>
{
public Movies_WithRentalsByUsersCount()
{
AddMap<MovieRental>(rentals =>
from r in rentals
select new ReducedResult
{
MovieId = r.MovieId,
UserRentalCounts = new[] { new UserRentalCount { UserId = r.UserId, Count = 1 } }
});
AddMap<Movie>(movies =>
from m in movies
select new ReducedResult
{
MovieId = m.Id,
UserRentalCounts = new[] { new UserRentalCount { UserId = null, Count = 0 } }
});
Reduce = results =>
from result in results
group result by result.MovieId
into g
select new
{
MovieId = g.Key,
UserRentalCounts = (
from userRentalCount in g.SelectMany(x => x.UserRentalCounts)
group userRentalCount by userRentalCount.UserId
into subGroup
select new UserRentalCount { UserId = subGroup.Key, Count = subGroup.Sum(b => b.Count) })
.ToArray()
};
}
public class ReducedResult
{
public string MovieId { get; set; }
public UserRentalCount[] UserRentalCounts { get; set; }
}
public class UserRentalCount
{
public string UserId { get; set; }
public int Count { get; set; }
}
}
public class User
{
public string Id { get; set; }
}
public class Movie
{
public string Id { get; set; }
}
public class MovieRental
{
public string Id { get; set; }
public string MovieId { get; set; }
public string UserId { get; set; }
}
}
}
Since your requirement says "for a given user", if you really are looking only for a single user, you can do this with a Multi-Map index. Use the Movies table itself to produce the baseline zero-count records and then map in the actual MovieRentals records for the user on top of that.
If you really need it for all users crossed with all movies, I don't believe there is a way to do this cleanly with RavenDB as this would be considered reporting which is noted as one of the sour spots for RavenDB.
Here are some options if you really want to try to do this with RavenDB:
1) Create dummy records in the DB for every user and every movie and use those in your index with a 0 count. Whenever a movie or user is added/updated/deleted, update the dummy records accordingly.
2) Generate the zero-count records yourself in memory on request and merge that data with the data that RavenDB gives you back for the non-zero counts. Query for all users, query for all movies, create the baseline zero-count records, then do the actual query for non-zero counts and layer that on top. Finally, apply paging/filtering/sorting logic.
3) Use the SQL replication bundle to replicate the Users, Movies, and MovieRental tables out to SQL and use SQL for this "reporting" query.

How to get data with #ManyToMany annotated tables?

My related tables are below.
Person Table
id
name
surname
Location Table
id
title
point
Person_Location Table
person_id
location_id
I want to get person and location values like this..
id | name | surname | title | point
1 john | adas | my home | 44,45
1 | John | adas | brother's home | 55,33
How can I get the users and their locations in hibernate?
try this out :
you can get an array of object and you can manipulat them as you want
String stringQuery="select p.id,p.name,p.surname,l.title,l.point from person p, location l,person_location pl where "
+ "p.id=pl.person_id and l.id=pl.location_id";
Query query=entityManager.createNativeQuery(stringQuery);
List<Object[]> result=query.getResultList();
later you can get the person Id by result.get(i)[0]
or you can create a custom class which will not be a managed entity:
public class customPerson{
id | name | surname | title | point
private int id;
private String name;
private String surname;
private String title;
private String doube point;
//getters&setters
//constructors (required) one default ant one with all your attributes
public CustomPerson(){}
public customPerson(int id,...){
...
}
}
later in your Dao you can get the result you want through the custom object:
String stringQuery="select p.id,p.name,p.surname,l.title,l.point from person p, location l,person_location pl where "
+ "p.id=pl.person_id and l.id=pl.location_id";
Query query=entityManager.createNativeQuery(stringQuery,CustomPerson.class);
List<CustomPerson> result=query.getResultList();
// In Person class:
#ManyToMany
#JoinTable(name="Person_Location",
joinColumns=
#JoinColumn(name="person_id", referencedColumnName="ID"),
inverseJoinColumns=
#JoinColumn(name="location_id", referencedColumnName="ID")
)
public Set<Locations> getLocations() { return locations; }
// In Location:
#ManyToMany(mappedBy="locations")
public Set<Person> getPersons() { return persons; }
In Person class
#OneToMany(mappedBy="person")
public Set<personLocations> getPersonLocation { return personLocations; }
In Location class
#OneToMany(mappedBy="location")
public Set<personLocations> getPersonLocation { return personLocations; }
In personLocations
#ManyToOne
#JoinColumn(name="person_ID")
public Person getPerson() { return person; }
#ManyToOne
#JoinColumn(name="location_ID")
public Location getlocation() { return location; }

Designing Classes: Each class encapsulate object of other related class

I am stuck with the design problem. I could not come up with any good solution. Here is the problem statement.
I have set of devices, each of these devices has some common properties and behavior. Each device may contain 1 or more than one other type of devices connected to it. For example : If there are 4 set of devices A,B,C,D and A being the root of all the devices.
A will have one or many B devices.
B will have one or many C devices.
C will have one or many D devices.
All these different set of devices have some common properties while some are exclusive to themselves.
I have to create a report which will read the data from these objects and read it to file. Report is in XML format and will depict hierarchy of whole system.
How could I approach this problem ? Any suggestion comment would be of great help.
This sounds like a case for the Visitor pattern. You let the Visitor visit each of the children of A. For each child, it'll again visit all children, and so on.
While the Visitor traverses the tree, you collect data about each node. You can, in this case, for example collect the data directly in XML if you want.
The Visitor pattern works well with heterogeneous data types, but it's OK when some of the nodes have common structure as well.
Visitor pattern is a better way of performing operations that where all parent and child classes should be accepted as input and in which behavior is dictated by the object type.
Here's C++ Implementation for your reference:
#include <vector>
#include <iostream>
using namespace std;
class Visitor
{
public:
virtual void visit(class Node *, class Common*) = 0;
virtual void visit(class CompositeNode *, Common*) = 0;
};
class Common
{
int value;
public:
Common(int val)
{
value = val;
}
virtual void traverse()
{
cout << value << " | ";
}
virtual void accept(Visitor &, Common*) = 0;
};
class Node: public Common
{
public:
Node(int val): Common(val){}
virtual void accept(Visitor &v, Common *c)
{
v.visit(this, c);
}
};
class CompositeNode: public Common
{
vector < Common * > children;
public:
CompositeNode(int val): Common(val){}
void add(Common *ele)
{
children.push_back(ele);
}
virtual void accept(Visitor &v, Common *c)
{
v.visit(this, c);
}
virtual void traverse()
{
Common::traverse();
for (int i = 0; i < children.size(); i++)
children[i]->traverse();
}
};
class AddVisitor: public Visitor
{
public:
virtual void visit(Node *, Common*)
{
}
virtual void visit(CompositeNode *node, Common *c)
{
node->add(c);
}
};
int main()
{
Common *nodes[3];
nodes[0] = new CompositeNode(0); //Consider A
nodes[1] = new CompositeNode(1); //Consider B
nodes[2] = new CompositeNode(2); //Consider B
AddVisitor addVisitor;
nodes[0]->accept(addVisitor, nodes[1]); //B
nodes[0]->accept(addVisitor, nodes[2]); //B
nodes[1]->accept(addVisitor, new Node(3)); //Consider C
nodes[1]->accept(addVisitor, new Node(4)); //Consider C
nodes[2]->accept(addVisitor, new Node(5)); //Consider C
nodes[2]->accept(addVisitor, new Node(6)); //Consider C
for (int i = 0; i < 3; i++)
{
cout<<"--------------------------------"<<endl;
nodes[i]->traverse();
cout<<endl;
}
}
Output
--------------------------------
0 | 1 | 3 | 4 | 2 | 5 | 6 |
--------------------------------
1 | 3 | 4 |
--------------------------------
2 | 5 | 6 |

Grammar refactoring for LL parsing

In a simple example, I'm confused about how to turn this grammar into a LL one by removing the left recursion. Any hints are welcome.
G = {
A -> A a | A B | a
B -> b
}
I get the following by applying this algorithm:
G = {
A -> a X
X -> e | A | B X
B -> b
}
This seem to work to generate a C pseudo-code for the parser:
void A() {
switch (token) {
case 'a' : next(); X(); break;
}
}
void X() {
switch (token) {
case 'e' : finish(); break;
case 'a' : A(); break;
case 'b' : B(); X(); break;
}
}
void B() {
next();
}
And to generate a parsing tree for the word: aabab:
A ---+
| |
a X
|
A ---+
| |
a X ---+
| |
B X
| |
b A ---+
| |
a X ---+
| |
B X
| |
b e
Well, I'm just not sure if it's right...
First, your grammar seems to accept sequences of as separated by single bs, so that no 2 b come together. (aaa...abaaaaa...abaaa...a) This should be equivalent to something like:
Q -> P | P b P
P -> a | a P

Return properties from subclass left joins when querying superclass in NHibernate

I have an ICriteria that returns properties from a superclass Animal. Now I want to include in the results several properties from a subclass, Bird. For other subclasses, these properties should return null. I am using table-per-subclass inheritance. Is there any way to do this without adding lots of DetachedCriteria? NHibernate already left joins on the subclass tables; is there a way to project values from those joins?
Update: I need to be able to sort and filter on the subclass properties, and the entire query needs to support paging.
Here is my model:
public abstract class Animal
{
public long Id { get; set; }
public string Name { get; set; }
}
public class Cat : Animal
{
public int WhiskerCount { get; set; }
}
public class Bird : Animal
{
public long WingSpan { get; set; }
}
Given the following tables:
Animal:
Id | Name
----+--------------
1 | Sylvester
2 | Tweety
3 | Maru
4 | Big Bird
Cat:
Id | WhiskerCount
----+--------------
1 | 6
3 | 12
Bird:
Id | Wingspan
----+--------------
2 | 0.5
4 | 10
I want the following result set:
Id | Name | Wingspan
----+------------+-------------
1 | Sylvester | <null>
2 | Tweety | 0.5
3 | Maru | <null>
4 | Big Bird | 10
var results = session.CreateCriteria<Animal>()
.List<Animal>()
.Select(a => new
{
Id = a.Id,
Name = a.Name,
Wingspan = (a is Bird) ? ((Bird)a).Wingspan : (int)null
});