NOTE

Prototype Pattern

Prototype-pattern notes with UML, Java and Go clone examples, plus a generic DAO example that returns cloned data.

Software Architecture & Engineering1 min readhistorical

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

PlantUML 图表

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