Abstract class design

Is this an acceptable design?

Abstract class

public abstract class SomethingBase { public abstract int Method1(int number1); public abstract int Method2(int number2); } public class Class1 : SomethingBase { public override int Method1(int number1) { //implementation } //i dont want this method in this class public override int Method2(int number2) { throw new NotImplementedException(); } } public class Class2 : SomethingBase { //i dont want this method in this class public override int Method1(int number1) { throw new NotImplementedException(); } public override int Method2(int number2) { //implementation } } 

I mean the situation if I need method1 in my class1 and method2 and vica verse for Class2. In fact, methods are mutually exclusive in derived classes.

+4
source share
8 answers

This is not an acceptable design. To make it more acceptable, you can implement two interfaces in an abstract class. One for Method1() and one for Method2() , and just use the interface object to pass it.

You really do not want to use the definitions of Class1 and Class2 , as there is a danger that your clients will call a method that is not implemented. Therefore, I suggest using interfaces and using them instead.

+9
source

I think there is something fundamentally wrong with your design. Two derived objects should be inferred only from the base class, which really represents the commonality between them. In your example, the base class does not represent a commonality between Class1 and Class2.

+4
source

Liskov replacement principle (aka LSP) is torn:

Let q (x) be a property provable with respect to objects x of type T. Then q (y) must be true for objects y of type S, where S is a subtype of T.

I also consider this an IS-A rule. If class B is derived from class A, it must support all the same functions as class A, and not violate its behavior in the process. If something consumes an object of class A, you should be able to pass an object of class B instead, and not interrupt it.

For example, suppose your base class is a Rectangle , and you get the Square class from it. You violated the LSP because the Rectangles may have a width not equal to their length, while a square cannot.

In your case, however, your base class is abstract, so the LSP is not perfect, but I think you understand what I get.

+4
source

Is this an acceptable design?

Not. I may be acceptable in some situations (e.g. ReadOnlyCollection in FCL), but you should avoid it where possible.

You can use two interfaces: one with Method1 and one with Method2.

You should always follow the rule that derived classes should not simplify the contract for the base class. They must be exchanged with the base class in your program.

+3
source

This is not an acceptable design because it violates the base class contract. Take, for example, the following customer code

 public void SomeFunction(SomethingBase x){ x. Method2(1); // This will fail for Class1 but will pass for Class2. This is faulty. } 

Instead, you can connect to an interface and have one interface containing Method1, and the second interface contains Method2.

 interface IM1{ int Method1(int number1); } interface IM2{ int Method2(int number2); } class Class1 : IM1{ int Method1(int number1){ // Implement your logic } } class Class2 : IM2{ int Method2(int number2){ // Implement your logic } } // Client Code public void SomeFunction(IM2 x){ x. Method2(1); // This will work as this is the only thing this client wants. } 
+3
source

I absolutely agree with the statement that the design you demonstrated should be avoided whenever possible in favor of interfaces.

But sometimes it is difficult to avoid or predict.

A classic example in .NET that uses the approach you mentioned is the Stream class, where some children throw a NotSupportedException for some abstract properties and methods. (for example, the Position property in the DeflateStream class.) But in order to correctly implement this design, you must have the virtual properties CanMethod1 or Method1Supported() . (As in TypeConverter - usually when you have more complex cases, mainly when the method is supported only in certain contexts.)

+3
source

First of all, if you do not define any member variables in an abstract class, I would probably just use interfaces.

Secondly, I will probably have only one method in an abstract class, and each of the classes will implement it differently (with their own specific logic), since the signatures of Method1 and Method2 seem to be the same.

+2
source

I did not agree with the majority of votes, but supported the Regent. You want to support and expand your position.

This is NOT ALWAYS a bad design for using a NotSupportedException. You have to weigh all the pros and cons.

What if you have a large number of classes with almost, but not exactly the same sets of methods? Threads are a good example. If you try to sort all of these methods in interfaces, this 1) gives you additional work on creating intuitive and concise names for all these interfaces, 2) makes the user of the interfaces understand what each of them does.

It is possible that throwing a NotSupportedException in one or two methods will be more understandable for the user of the class library, and then will examine the complex interface and class hierarchy.

+1
source

All Articles