-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
158 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
--- | ||
title: Prototype | ||
date: 2024-06-06 23:18:41 | ||
tags: | ||
- Design Patterns | ||
- Creational Patterns | ||
categories: Design Patterns | ||
--- | ||
**Prototype** is a creational design pattern that lets you copy existing objects without making your code dependent on their classes. | ||
|
||
<!-- more --> | ||
<br> | ||
|
||
## Problem | ||
|
||
Say you have an object, and you want to create an exact copy of it. How would you do it? First, you have to create a new object of the same class. Then you have to go through all the fields of the original object and copy their values over to the new object. | ||
|
||
Nice! But there’s a catch. Not all objects can be copied that way because some of the object’s fields may be private and not visible from outside of the object itself. | ||
|
||
There’s one more problem with the direct approach. Since you have to know the object’s class to create a duplicate, your code becomes dependent on that class. If the extra dependency doesn’t scare you, there’s another catch. Sometimes you only know the interface that the object follows, but not its concrete class, when, for example, a parameter in a method accepts any objects that follow some interface. | ||
|
||
---- | ||
|
||
## Solution | ||
|
||
The Prototype pattern delegates the cloning process to the actual objects that are being cloned. The pattern declares a common interface for all objects that support cloning. This interface lets you clone an object without coupling your code to the class of that object. Usually, such an interface contains just a single `clone` method. | ||
|
||
The implementation of the `clone` method is very similar in all classes. The method creates an object of the current class and carries over all of the field values of the old object into the new one. You can even copy private fields because most programming languages let objects access private fields of other objects that belong to the same class. | ||
|
||
An object that supports cloning is called a *prototype*. When your objects have dozens of fields and hundreds of possible configurations, cloning them might serve as an alternative to subclassing. | ||
|
||
Here’s how it works: you create a set of objects, configured in various ways. When you need an object like the one you’ve configured, you just clone a prototype instead of constructing a new object from scratch. | ||
|
||
---- | ||
|
||
## Prototype in Java | ||
|
||
Let’s take a look at how the Prototype can be implemented without the standard `Cloneable` interface. | ||
|
||
**shapes/Shape.java: Common shape interface** | ||
|
||
```java | ||
public abstract class Shape { | ||
public int x; | ||
public int y; | ||
public String color; | ||
|
||
public Shape() { | ||
} | ||
|
||
public Shape(Shape target) { | ||
if (target != null) { | ||
this.x = target.x; | ||
this.y = target.y; | ||
this.color = target.color; | ||
} | ||
} | ||
|
||
public abstract Shape clone(); | ||
|
||
@Override | ||
public boolean equals(Object object2) { | ||
if (!(object2 instanceof Shape)) return false; | ||
Shape shape2 = (Shape) object2; | ||
return shape2.x == x && shape2.y == y && Objects.equals(shape2.color, color); | ||
} | ||
} | ||
``` | ||
|
||
**shapes/Circle.java: Simple shape** | ||
|
||
```java | ||
public class Circle extends Shape { | ||
public int radius; | ||
|
||
public Circle() { | ||
} | ||
|
||
public Circle(Circle target) { | ||
super(target); | ||
if (target != null) { | ||
this.radius = target.radius; | ||
} | ||
} | ||
|
||
@Override | ||
public Shape clone() { | ||
return new Circle(this); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object object2) { | ||
if (!(object2 instanceof Circle) || !super.equals(object2)) return false; | ||
Circle shape2 = (Circle) object2; | ||
return shape2.radius == radius; | ||
} | ||
} | ||
``` | ||
|
||
**Demo.java: Cloning example** | ||
|
||
```java | ||
public class Demo { | ||
public static void main(String[] args) { | ||
List<Shape> shapes = new ArrayList<>(); | ||
List<Shape> shapesCopy = new ArrayList<>(); | ||
|
||
Circle circle = new Circle(); | ||
circle.x = 10; | ||
circle.y = 20; | ||
circle.radius = 15; | ||
circle.color = "red"; | ||
shapes.add(circle); | ||
|
||
Circle anotherCircle = (Circle) circle.clone(); | ||
shapes.add(anotherCircle); | ||
|
||
Rectangle rectangle = new Rectangle(); | ||
rectangle.width = 10; | ||
rectangle.height = 20; | ||
rectangle.color = "blue"; | ||
shapes.add(rectangle); | ||
|
||
cloneAndCompare(shapes, shapesCopy); | ||
} | ||
|
||
private static void cloneAndCompare(List<Shape> shapes, List<Shape> shapesCopy) { | ||
for (Shape shape : shapes) { | ||
shapesCopy.add(shape.clone()); | ||
} | ||
|
||
for (int i = 0; i < shapes.size(); i++) { | ||
if (shapes.get(i) != shapesCopy.get(i)) { | ||
System.out.println(i + ": Shapes are different objects (yay!)"); | ||
if (shapes.get(i).equals(shapesCopy.get(i))) { | ||
System.out.println(i + ": And they are identical (yay!)"); | ||
} else { | ||
System.out.println(i + ": But they are not identical (booo!)"); | ||
} | ||
} else { | ||
System.out.println(i + ": Shape objects are the same (booo!)"); | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
**Execution result:** | ||
|
||
``` | ||
0: Shapes are different objects (yay!) | ||
0: And they are identical (yay!) | ||
1: Shapes are different objects (yay!) | ||
1: And they are identical (yay!) | ||
2: Shapes are different objects (yay!) | ||
2: And they are identical (yay!) | ||
``` | ||
|