I have this case where I am extending from a super class with methods being typed using Generics as the following:
Models
abstract class SuperClass {
//.....
}
class SubClass extends SuperClass {
int a;
int b;
String c;
//....
}
Controllers
abstract class A {
T getDoc<T extends SuperClass>(T doc);
}
class B extends A {
T getDoc<T extends SubClass>(T doc) { //<================ Error
//....
}
}
Basically class B will only deal with a SubClass model and any class that extends it. Extending SuperClass is not enough. It's a way to enforce the type usage. I could add a helper function that will check the type for each method within class B (doc is SubClass) but seems like a lot repetition.
But the above architecture fails when overriding the method getDoc in class B saying that it isn't a valid override although SubClass is a SuperClass. How can I achieve something like this? Or is there a better way of doing it? Appreciate any pointers :)
I have finally a found a way :)
So I wanted the class B's methods to accept exclusively types that extend SubClass, but class A method's signature expects parameters extending class SuperClass.
To go about this I did the following:
Models
abstract class SuperClass {
//.....
}
class SubClass extends SuperClass {
int a;
int b;
String c;
//....
}
Controllers
abstract class A<K extends SuperClass> {
T getDoc<T extends K>(T doc);
}
class B extends A<SubClass> {
T getDoc<T extends SubClass>(T doc) {
//.......
}
}
can you use covariant modifier.
In your example:
abstract class A {
T getDoc<T extends SuperClass>(covariant T doc);
}
Check: https://github.com/dart-lang/sdk/blob/master/docs/language/informal/covariant-overrides.md
You can not narrow the generic type argument. Class B guaranties (by extending class A), that it will/can handle all type arguments (and sub types!), that class A can handle. Consider the following situation:
class OtherSubClass extends SuperClass {
//....
}
void main() {
var b = B();
b.getDoc(OtherSubClass());
}
What would you expect to happen? Class B is not able to handle objects of type OtherSubClass, so it breaks the contract with class A.
Related
I have a problem to chose the between an abstract class without abstract methods OR a base class with an interface.
I have two implementation in my mind:
1.
Let's say I have a AbstractRenderer:
abstract class AbstractRenderer
{
protected $shape;
public function __construct(AbstractShape $shape)
{
$this->shape = $shape;
}
public function render(): string
{
return $this->shape->generate()->asArray();
}
}
and the WebRenderer would be like this:
class WebRenderer extends AbstractRenderer
{
}
2.
Have a base class and an interface like this:
Interface InterfaceRenderer
{
public function __construct(AbstractShape $shape);
public function render(): string;
}
and a base class that impediments the interface:
class BaseRenderer implements InterfaceRenderer
{
protected $shape;
public function __construct(AbstractShape $shape)
{
$this->shape = $shape;
}
public function render(): string
{
return $this->shape->generate()->toString();
}
}
again, my WebRenderer would be like this:
class WebRenderer extends BaseRenderer
{
}
I don't know which is the correct implementation, or there is a better way to implement this and what is the pros and cons of each.
Thanks
From the Renderer client’s perspective the 2 solutions are basically identical. As long as they depend on an abstract object (interface or an abstract class), you’ll have benefits of polymorphism. You’d lose those if you make them depend on WebRenderer (concrete object).
Interface’s benefits over abstract classes
doesn’t occupy inheritance
no fragile base class problem
Abstract classes provide
static methods (in many languages interface can’t have these)
protected implementation
I have two questions:
I have a Singleton class with a property Layout that I use in creating child objects of an abstract class (example below). The abstract class has an abstract method where the layout file is given as a variable. Do I connect that Singleton class to the abstract class or each child? The following example is written using pseudo-code:
public class SingletonClass
{
public static Instance;
public var[,] Layout;
}
public abstract class AbstractClass
{
public abstract void DoSomething(var[,] Layout);
}
public class ClassA : AbstractClass
{
public override void DoSomething(var[,] Layout) { some code }
}
public class ClassB : AbstractClass
{
public override void DoSomething(var[,] Layout) { some other code }
}
Is it even needed, or "cleaner", to give the Layout as variable in the method, or is it ok to just call Layout from the singleton class?
The following UML is an equivalent of your code
under the following assumptions: Instance and Layout are assumed to be attributes of analogous classes.
SingletonClass has two owned attributes (denoted by the big dots): public layout of type Layout and instance of type AbstractClass (it's abstract, hence the italics). The latter will later hold either an instance of the concrete ClassA or ClassB.
Whether or not the design is ok depends. Basically there's nothing wrong with this.
Suppose I have a class called A and there are two versions to it A1 and A2.
class A{};
class A1 : A{};
class A2 : A{};
and I have one more class which would use these.
class B
{
B(A obj)
{
if(obj.type(A1)){}//do this
else(obj.type(A2)){})//do this
}
}
Questions:
1) Suppose there are 100 or 1000 of classes derived from A,then how do I implement it in the constructor of B, by using "switch" or "if"> In both cases if I have to extend the class I will violate the "open closed principle".
2) if(obj.type(A1)) is this implementation the best way to implement for detecting which class object is there.
If you have a 100 classes derived from the same base class, you need to re-consider your design.
That said, sometimes you have a large number of classes doing similar things.
One option is to use an interface, have your different classes implement that interface, and the "do this" implemented in each subclass separately:
class B { B(A obj) {
if(obj.type(A1)){}//do this
else(obj.type(A2)){})//do this
} }
becomes
interface AInterface
{
public void doThis();
}
abstract class A implements AInterface
{
...
}
class A1 extends A
{
public void doThis()
{
...
}
}
class A2 extends A
{
public void doThis()
{
...
}
}
class B { B(AInterface obj) {
obj.doThis();
} }
Another, more advanced approach is to use the Visitor design pattern.
I have some classes:
class ClassA implements InterfaceA {
public function load(Foo $foo) {
}
}
interface InterfaceA {
public function load(InterfaceFoo $foo);
}
class Foo implements InterfaceFoo
{
}
My question is why is my ClassA::load(Foo $foo) method not compatible with my InterfaceA::load(InterfaceFoo $foo) even though class Foo implements InterfaceFoo?
I know I can write my ClassA as follows:
class ClassA implements InterfaceA {
public function load(InterfaceFoo $foo) {
if (!($foo instanceof Foo)) {
throw new Exception("InterfaceFoo must be an instance of Foo");
}
}
}
but I still am confused why the previous way doesn't work.
You can not do that because it violates the InterfaceA contract.
load method says it can work with any concrete implementation of InterfaceFoo, not only the specific one.
This is called polymorphism and is good.
You can dinamically downcast foo param in your load method to check if it's some concrete implementation like Foo.
I have a question on object-oriented programming.
If there is a attribute which has different value in sub-classes. It should create a abstract accessor in the super-class, then override it in the sub-classes. Or create a protected instance variable in base-class, and assign the default value in the sub-class constructor?
Let's see the code example code:
Choice 1:
class BaseClass {
public abstract int GetFoo();
}
class SubClass {
public int GetFoo() {
return -1;
}
}
Choice 2:
class BaseClass {
protected int _foo;
public int GetFoo() {
return _foo;
}
}
class SubClass {
public SubClass() {
_foo = -1;
}
}
Or any ideas?
I would go with the first approach of providing a getter that can be overridden in the derived classes to provide a different value, instead of creating protected members in my class which are also package-private and violate the encapsulation principle.