NOTE
Prototype Pattern
Prototype-pattern notes with UML, Java and Go clone examples, plus a generic DAO example that returns cloned data.
This is a historical learning note and may contain outdated or incomplete understanding.
Creating an object may require a lot of data preparation; instead, use an existing object as a prototype, clone it, and then modify the value.
1. UML
2. Java
2.1. Client
public class Client
{
public static void main(String[] args) throws CloneNotSupportedException
{
Sheep sheep = new Sheep();
sheep.setName("prototype sheep");
sheep.setDateTime(LocalDateTime.now());
Sheep sheep1 = (Sheep)sheep.clone();
sheep1.setName("cloned sheep");
// Both timestamps are the same
System.out.println(sheep);
System.out.println(sheep1);
System.out.println(sheep.getDateTime().equals(sheep1.getDateTime()));
System.out.println("**********************");
// Change sheep's timestamp; sheep1 should remain unchanged
sheep.setDateTime(LocalDateTime.now());
// The timestamps should now differ
System.out.println(sheep);
System.out.println(sheep1);
System.out.println(sheep.getDateTime().equals(sheep1.getDateTime()));
}
}
2.2. Sheep
public class Sheep implements Cloneable// implement the Cloneable interface
{
private String name;
// immutable, so no additional cloning is required
private LocalDateTime dateTime;
@Override// override clone
public Object clone() throws CloneNotSupportedException
{
Object object = super.clone();
// For a deep copy, recursively clone each field
return object;
}
@Override
public String toString()
{
return "Sheep{" + "name='" + name + '\'' + ", dateTime=" + dateTime + '}';
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public LocalDateTime getDateTime()
{
return dateTime;
}
public void setDateTime(LocalDateTime dateTime)
{
this.dateTime = dateTime;
}
}
3. Golang
3.1. Sheep
// Cloneable is the interface a prototype object must implement
type Cloneable interface {
Clone() Cloneable
}
type Sheep struct {
Name string
}
func NewSheep(name string) *Sheep {
return &Sheep{Name: name}
}
func (s *Sheep) Clone() Cloneable {
sClone := *s
return &sClone
}
3.2. Client
func main() {
sheep := prototype.NewSheep("strong sheep")
cloneSheep := sheep.Clone()
fmt.Println(sheep == cloneSheep)
}
4. Example
// globalItemDao ...
var globalItemDao = &ItemDao{
mutex: new(sync.RWMutex),
}
// ItemDao ...
type ItemDao struct {
mutex *sync.RWMutex
items map[int64]*model.Item
}
// GetItemDaoInstance ...
func GetItemDaoInstance() *ItemDao {
return globalItemDao
}
// UpdateItems ...
func (a *ItemDao) UpdateItems(ctx context.Context,
items []*model.Item) {
m := make(map[int64]*model.Item)
for _, item := range items {
m[item.Id] = item
}
a.mutex.Lock()
a.items = m
a.mutex.Unlock()
}
// GetItemById ...
func (a *ItemDao) GetItemById(itemId int64) *model.Item {
a.mutex.RLock()
defer a.mutex.RUnlock()
return clone.Clone(a.items[itemId]).(*model.Item)
}
// GetAllItems
func (a *ItemDao) GetAllItems() map[int64]*model.Item {
a.mutex.RLock()
defer a.mutex.RUnlock()
return clone.Clone(a.items).(map[int64]*model.Item)
}
Discussion
Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub