With a strong increase in the number of fields and methods of a class, there is a desire to divide it into semantic parts and aggregate them into the main class as field objects. But the problem is that the descendants of the main class raise the question of extending the functionality, and for this you want to inherit from the aggregated classes the expanded new ones and replace the old ones with them. And this just can not be done! Example (ActionScript 3, all classes are scattered over the same file):

public class ContainerA { public var subClass: SubClassA; public function ContainerA() { initSubclasses(); } protected function initSubclasses(): void { subClass = new SubClassA(); } } public class ContainerB extends ContainerA { // ошибка компилирования! ΠΏΠ΅Ρ€Π΅Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ ΠΌΠΎΠΆΠ½ΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ override public var subClass: SubClassB; public function ContainerB() { super(); } override protected function initSubclasses(): void { subClass = new SubClassB(); } } public class SubClassA { public function PrintA(): void { trace("I'm a subclass A"); } } public class SubClassB extends SubClassA { override public function PrintA(): void { trace("I'm a subclass B, inherited from A"); } public function PrintB(): void { trace("I'm a subclass B"); } } 

code in Main.as:

 var containerA: ContainerA = new ContainerA(); var containerB: ContainerB = new ContainerB(); containerA.subClass.PrintA(); // " I'm a subclass A " containerB.subClass.PrintA(); // " I'm a subclass B, inherited from A " containerB.subClass.PrintB(); // Π½Π°ΠΏΠ΅Ρ‡Π°Ρ‚Π°Π»ΠΎΡΡŒ Π±Ρ‹ " I'm a subclass B " 

Even if, instead of overloading the field, you do an overload of the get method and access the aggregated class through it, a compilation error will also occur, but this is different: you cannot change the signature of the overloaded method:

in ContainerA:

 public function getSubClass(): SubClassA { return subClass; } 

in ContainerB:

 override public function getSubClass(): SubClassB { return (subClass as SubClassB); } 

Therefore, the question is: how are these problems solved (if they are solved) in ActionScript and how are they solved in other statically typed languages ​​(Java, C #). Maybe there are some crutch, but convenient design patterns?

  • 2
    This is called "covariance (i.e. narrowing) of the return type." This is not in C # or ActionScript, but in Java (JDK 1.5+) this is implemented - en.wikipedia.org/wiki/Covariant_return_type - d9k
  • It became interesting - provide the resulting code. And Vika right now, alas, lies ( - wind


1 answer 1

  • What you are trying to do is incorrect, because you are trying to change the signature of the method already defined in the base class in your derived class, and your SubClassB not inherited from SubClassA .

Without loss of generality, we can talk about public fields, which theoretically could be equivalent to replace with a get/set pair.

  • Imagine the following case:

     var b: ContainerB = new ContainerB(); var a: ContainerA = b as ContainerA; // Какой compile-time Ρ‚ΠΈΠΏ, ΠΏΠΎ-Π²Π°ΡˆΠ΅ΠΌΡƒ, Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ Ρƒ этих ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ²? var x: ??? = a.subClass; var y: ??? = a.getSubClass(); 
  • If your SubclassB was inherited from SubClassA , then in your 'getSubClass() : SubClassA' you could do a 'return new SubClassB();' , and it would be the right solution to the problem.

At the moment when you return a SubClassA from the method that SubClassA should return, a type contravariance.

  • one
    > public class SubClassB>> {>> override public function PrintA (): void>> {>> trace ("I'm a subclass B, inherited from A"); >>} It looks like @ d9k implies that SubClassB inherited from SubClassA , but he forgot to write extends... - Nofate ♦
  • Yes, I copied the code and forgot, thanks - d9k