javadesign-patternsliskov-substitution-principleprototype-pattern

Does the Prototype pattern violate the Liskov substitution principle?


I'm revisiting design patterns, especially those that I haven't used for a while/or at all. And one of them is the Prototype pattern.

Different sources (e.g. this one) say that you should implement the Clonable interface and override the clone() method to implement the Prototype pattern in Java. But it also says:

implementing clone() can be difficult when their internals include objects that don’t support copying or have circular references.

This makes sense to me, e.g. if there is some GameCharacter super class, and a dozen of child classes that share the same base state, but some of which may be 'unique' (i.e. not clonable) and some may not (i.e. clonable).

But doesn't it violate the Liskov substitution principle? It says

objects of a superclass should be able to be replaced with objects of a subclass without affecting the correctness of the program

but in the case described above LSP will be violated, right? Non-cloneable objects will throw a CloneNotSupportedException in case of calling the clone(), which is affecting the correctness of the program. Am I missing something?

Although I've not worked with really huge classes yet, so far I've always used constructors like the following, and they were doing their job well:

@Getter
@Setter
public class Tst {

private String prop1;
private Prop2 prop2;
......

public Tst(Tst sourceObj) {
     Tst targetObj  = new Tst()
     this.setProp1(sourceObj.getProp1())
     this.setProp2(new Prop2(sourceObj.getProp2()))
  .....
}

}

You put such a constructor in the class where it is needed and call it in the required place with casting.

So are there some real cases when the Prototype pattern gives a big profit nowadays? Or in most cases it's just an overkill?


Solution

  • The title asks,

    Does the Prototype pattern violate the Liskov substitution principle?

    We can easily answer no to this. Design Patterns don't force violations, because design patterns don't specify a particular implementation. There are innumerable ways to implement a design pattern, by definition.

    But the actual question here seems to be,

    Can the Prototype pattern violate the Liskov substitution principle?

    We can easily answer yes to this. Design Patterns can violate a principle if they are implemented to do so. The OP describes one example of how it could happen with game characters.

    Copy Constructors are a great alternative in Java, or potentially something like @With from Lombok, depending on your requirement.