Deo zbornika Uvod u softversko inženjerstvo

Komanda (projektni obrazac)

Komanda (command pattern) razdvaja onog ko zahteva akciju od onog ko je izvršava. Komandni obrazac omogućava da se akcije ili komande smeste u objekat, omogućujući njihovo fleksibilno izvršenje, poništenje ili odlaganje. Na taj način se olakšava rukovanje akcijama, uključujući i vraćanje na prethodno stanje.

Analogija komandnog obrasca iz stvarnog života bila bi poručivanja hrane u restoranu.

Opcije

Komandni obrazac omogućava da se komande tretiraju kao objekti. Na taj on podržava:

  • dodavanje nove komande bez menjanja postojećeg koda.
  • poništenje (undo) i ponovo izvršenje (redo) komande.
  • odlaganje komandi za kasnije izvršenje.
  • smeštanje zahteva u redove, logovanje i odbijanje zahteva
  • slanje zahteva ka različitim objektima
  • kreiranje transakcija višeg nivoa od primitivnih operacija

Primer: upravljanje dokumentima (undo/redo)

class Document {
  constructor() {
    this.content = ''
  }

  addText(text) {
    this.content += text
    console.log(`Dodano: "${text}" | Trenutni sadržaj: ${this.content}`)
  }

  removeText(text) {
    this.content = this.content.replace(text, '')
    console.log(`Uklonjeno: "${text}" | Trenutni sadržaj: ${this.content}`)
  }
}

class Command {
  constructor(execute, undo) {
    this.execute = execute
    this.undo = undo
  }
}

class History {
  constructor() {
    this.commands = []
    this.index = -1
  }

  execute(command) {
    command.execute()
    this.commands.splice(this.index + 1)
    this.commands.push(command)
    this.index++
  }

  undo() {
    if (this.index >= 0) {
      this.commands[this.index--].undo()
    }
  }

  redo() {
    if (this.index < this.commands.length - 1) {
      this.commands[++this.index].execute()
    }
  }
}

const document = new Document()
const history = new History()

const addHello = new Command(
  () => document.addText('Hello '),
  () => document.removeText('Hello ')
)

const addWorld = new Command(
  () => document.addText('World!'),
  () => document.removeText('World!')
)

history.execute(addHello)
history.execute(addWorld)

history.undo()
history.redo()

Primer: upravljanje pozadinskim procesima

Ovaj primer koristi komandni obrazac za upravljanje zadacima u pozadini, kao što su slanje email-a, čuvanje podataka u bazi itd.

class BackgroundTaskExecutor {
  constructor() {
    this.tasks = []
  }

  addTask(task) {
    this.tasks.push(task)
  }

  executeAll() {
    this.tasks.forEach(task => task())
  }
}

const emailService = { 
  send: email => console.log(`Slanje email-a na adresu: ${email}`)
}

const databaseService = { 
  save: data => console.log(`Čuvanje podataka u bazi: ${JSON.stringify(data)}`)
}

const sendEmailTask = () => emailService.send('example@example.com')
const saveDataTask = () => databaseService.save({ userId: 1, name: 'John Doe' })

const taskExecutor = new BackgroundTaskExecutor()
taskExecutor.addTask(sendEmailTask)
taskExecutor.addTask(saveDataTask)

taskExecutor.executeAll()

Literatura

  • Zdravko Ivanković i Dejan Lacmanović, Softversko inženjerstvo 2 (skripta), Tehnički fakultet Mihajlo Pupin, Zrenjanin
  • Angelina Njeguš, Obrasci projektovanja softvera, Univerzitet Singidunum, Beograd, 2023.