I have a design problem and I can't find the right way to deal with that. In my problem there are 4 classes:
class G
class T depending on the G
class F depending on T
class P depending on G, T and F
Additionally each concrete implementation of P should use exact implementation of T and when F is used then T is not needed. However F and T are different concepts (I would say F is some transformation or different interpretation of T) and it is hard to design common interface for them (otherwise I would think about decorator pattern). I was thinking about approach like below:
class PImpl extends P {
G g;
T t;
F f;
PImpl(G g) {
this.g = g;
this.t = new TImpl(g);
this.f = new FImpl(t);
}
}
But isn't it breaking the Dependency Inversion Principle from SOLID? Another idea which is an extenstion of above is additional introduction of initialization method for TImpl and FImpl. Then I would provide implementation classes in the constructor and then do exact construction in the constructor body.
class Test {
main() {
P p = new PImpl(new GImpl(), new FImpl());
}
}
abstract class P {
G g;
T t;
F f;
P(G g, T t, F f) {
this.g = g;
this.t = t.create(g);
this.f = f.create(t);
}
}
class PImpl extends P {
PImpl(G g, F f) {
super(g, new TImpl(), f);
}
}
But I'm not sure if this brings any additional value and only makes the code more complex.
Related
I have a many-to-many relation, having P, PF and F I want to filter P using F through PF. Like:
final query = Query<P>(context)
..where( (p)=>p.pfSet.firstWhere( (pf)=>pf.f.cod == 1 ).f ).isNotNull();
and the classes:
class P extends ManagedObject<_P> implements _P {}
class _P{
#primaryKey
int cod;
...
ManagedSet<ProdutoFilial> pfSet;
}
class PF extends ManagedObject<_PF> implements _PF {}
class _PF{
#primaryKey
int cod;
#(Relate #pfSet)
P p;
#(Relate #pfSet)
F f;
bool active;
}
class F extends ManagedObject<_F> implements _F {}
class _F{
#primaryKey
int cod;
...
ManagedSet<ProdutoFilial> pfSet;
}
How can I filter this?
Can use a own query that will stay on where:
..predicate = QueryPredicate(
" exists (select f.cod from pf where pf.fcod = #fcod and pf.pcod = p.cod) ",
{ "fcod": 1 });
if you use join in your code query the table name will change.
QueryPredicate is not a very good solution because you cannot set a condition in a joined table (we don't know the aliases of joined tables). I created my own procedure - try it:
QueryExpression<dynamic, dynamic> RelationWhereExt(Query query, List<String> links) {
ManagedEntity e = query.entity;
KeyPath path;
ManagedPropertyDescription property;
links.forEach((link) {
property = e.properties[link];
if (path==null){
// рутовое условие
path = KeyPath(property);
} else {
// следующие условия
path.add(property);
}
if (property is ManagedRelationshipDescription) {
e = (property as ManagedRelationshipDescription).destinationEntity; // меняем entity
}
});
QueryExpression<dynamic, dynamic> queryExpression = QueryExpression<dynamic, dynamic>(path);
(query as MySqlQuery).expressions.add(queryExpression);
return queryExpression;
}
In you case: RelationWhereExt(query, ['pfSet', 'f']).isNotNull();
I'm trying to learn OOP and OOD principles in correct way. I would like to get some clarification on Liskov substitution principle and their PRE and POST conditions. I have read some topics here, some articles from http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod and other places.
I have written a simple base class and several example sub classes with my assumptions on pre and post conditions for very of them and i would like to know if they are correct.
Comment lines is what i think: is it violates or not PRE and POST conditions.
public abstract class BaseClass
{
public virtual int GetResult(int x, int y)
{
if (x > 10 && y < 20)
{
return y - x;
}
throw new Exception();
}
}
public class LSPExample1 : BaseClass
{
public override int GetResult(int x, int y)
{
// PRE: weakened pre condition is ok
if (x > 10 && y <= 15)
{
// POST: Is it ok? because the available result range is narrowed by y <= 15
return y - x;
}
throw new Exception();
}
}
public class LSPExample2 : BaseClass
{
public override int GetResult(int x, int y)
{
// PRE: Same as base - OK
if (x > 10 && y < 20)
{
// POST: I assume it's bad because of parameters place changed in substraction ?
return x-y;
}
throw new Exception();
}
}
public class LSPExample3 : BaseClass
{
public override int GetResult(int x, int y)
{
// PRE Condition is bad (Strenghtened) because of (X >5) and (Y>20) ?
if (x > 5 && y > 20)
{
// POST condition is ok because base class do substraction which is weaker than multiplication ?
return x * y;
}
throw new Exception();
}
}
I would really appreciate your time
This is one of those wonderful situations where you can actually go to the source. Barbara Liskov's original paper is available and quite accessible and easy to read. http://csnell.net/computerscience/Liskov_subtypes.pdf
All four GetResult methods you show accept two integers as input and either return an integer, or throw an exception. In this respect they all have the same behavior so it could be said that LSP is fully satisfied. Without explicit pre/postconditions or invariants, nothing else can really be said about the code.
What is missing in your example is the contract. What does GetResult require from its caller and what does it guarantee it will produce?
If, for example, the contract guarantees that the return value will equal y - x then Examples 2 and 3 fail the contract and therefore break LSP. If, however, the only guarantee is that the return value will be an Int or Exception, then they all pass.
If the contract guarantees that and exception will be thrown if x <=10 || y >= 20 then Example 1 & 3 break LSP. If the only guarantee is that the method will return an Int or throw an Exception, then they all satisfy it.
The code can't tell you what the guarantees are, it can only tell you want the code does.
Since I'm getting lots of up-votes, I'll add an example (pseudo-code):
class Line {
int start
int end
int length() { return end - start } // ensure: length = end - start
void updateLength(int value) {
end = start + value
// ensure: this.length == value
}
}
The "ensure" clause in each of the two functions are guarantees regarding the state of a Line object after the function is called. As long as I satisfy the guarantees in sub-classes, my sub-class will conform to LSP. So for example:
class Example1: Line {
void updateLength(int value) {
start = end - value
}
}
The above satisfies LSP.
If the Line's updateLength function also has an ensure clause of "this.start unchanged" then my subclass would not satisfy LSP.
I am new to c++/cli, the situation I faced is that:
the project I am doing needs to use an external dll, in my functions I need to use classes A, B and C which are from this dll, I put them in my .h file, the .h file looking like:
#include library I use
public ref class MyClass
{
public:
MyClass();
~MyClass();
otherfuc();
private:
A *a;
B *b;
C *c;
}
My .cpp file looking like:
MyClass::MyClass()
{
a = new A();
b = new B(*a);
c = b->func(); //error happened
}
MyClass::otherfunc()
{
c->func_c()
}
Class A, B, C are unmanaged class, so I only have one way to declare them in managed class, just like I do in the header file. In class B, it has a function which is called func, this function return class type C, I tried c = &b->func(), in this way, it will throw AccessViolationException, if I tried c = b->func, then the error is function call missing argument. What should I do, please help!!!
From what you've written my guess is that B::func() is declared to return a C instance as a temporary:
class B {
public:
C func();
};
Allocate an instance of C as a copy of temporary:
class A {
};
class C {
public:
C(int _i) : i(_i) {}
int func_c() { return i; }
int i;
};
class B {
public:
B(A & a) {}
C func() { return C(5); }
};
public ref class MyClass {
public:
MyClass();
~MyClass();
int otherfunc();
private:
A *a;
B *b;
C *c;
};
MyClass::MyClass()
{
a = new A();
b = new B(*a);
c = new C(b->func());
}
MyClass::~MyClass() {
delete a;
delete b;
delete c;
}
int MyClass::otherfunc()
{
return c->func_c();
}
void f() {
MyClass^ mc = gcnew MyClass();
int i = mc->otherfunc();
}
This assumes C is copyable (or moveable) and that copying it make sense for what you are doing.
How do i test that an object is an instance of a particular class in D?
Something akin to Javascript's instanceof keyword?
Use cast. It returns a null reference when you attempt to cast to a subclass it isn't an instance of (like C++'s dynamic_cast).
auto a = new Base;
auto b = cast(Child) a;
assert(b is null);
a = new Child;
auto c = cast(Child) a;
assert(c !is null);
typeid expression can tell you if instance is of some exact type (without considering inheritance hierarchy):
class A {}
class B : A {}
void main()
{
A a = new B();
// dynamic
assert( typeid(a) == typeid(B) );
// static
assert( typeid(typeof(a)) == typeid(A) );
}
In C I can do something like this
struct Point {
int x,y;
}
struct Circle {
struct Point p; // must be first!
int rad;
}
void move(struct Point *p,int dx,int dy) {
....
}
struct Circle c = .....;
move( (struct Point*)&c,1,2);
Using this approach, I can pass any struct(Circle,Rectangle,etc) that has struct Point as first member.
How can I do the same in google go?
Actually, there's a simpler way to do it, which is more similar to the OP's example:
type Point struct {
x, y int
}
func (p *Point) Move(dx, dy int) {
p.x += dx
p.y += dy
}
type Circle struct {
*Point // embedding Point in Circle
rad int
}
// Circle now implicitly has the "Move" method
c := &Circle{&Point{0, 0}, 5}
c.Move(7, 3)
Also notice that Circle would also fulfill the Mover interface that PeterSO posted.
http://golang.org/doc/effective_go.html#embedding
Although Go has types and methods and
allows an object-oriented style of
programming, there is no type
hierarchy. The concept of “interface”
in Go provides a different approach
that we believe is easy to use and in
some ways more general. There are also
ways to embed types in other types to
provide something analogous—but not
identical—to subclassing. Is Go an
object-oriented language?, FAQ.
For example,
package main
import "fmt"
type Mover interface {
Move(x, y int)
}
type Point struct {
x, y int
}
type Circle struct {
point Point
rad int
}
func (c *Circle) Move(x, y int) {
c.point.x = x
c.point.y = y
}
type Square struct {
diagonal int
point Point
}
func (s *Square) Move(x, y int) {
s.point.x = x
s.point.y = y
}
func main() {
var m Mover
m = &Circle{point: Point{1, 2}}
m.Move(3, 4)
fmt.Println(m)
m = &Square{3, Point{1, 2}}
m.Move(4, 5)
fmt.Println(m)
}