简体   繁体   中英

Composite design pattern in Scala?

In java I can implement the composite design pattern as follows:

interface Component{
    void operation();

}

class Composite implements Component{
    @override
    public void operation(){
       for(Child child in children){
           child.operation();
       }
    }        

    public void add(Component child){//implementation}
    public void remove(Component child){//implementation}
    public void getChild(int index);
 }

 class Leaf implements Component{
      @override
      public void operation(){
         //implementation
      }
 }

How can I write it in scala? In particular I am having trouble understanding how to write an interface and implement it?

In Scala, a Trait without any concrete methods is just an interface. So a direct translation would be:

trait Component { def operation(): Unit }

class Composite extends Component {
  def operation() = children foreach { _.operation() }
  def add(child: Component) = ...
  def remove(child: Component) = ...
  def getChild(index: Int) = ...
}

class Leaf extends Component {
  def operation() = ...
}

Though if you want more idiomatic Scala, I'd recommend something like this as a definition for Composite :

class Composite extends Component {
  def operation() = children foreach { _.operation() }
  def +=(child: Component) = ...
  def -=(child: Component) = ...
  def apply(index: Int) = ...
}

To be used as:

val comp = new Composite
comp += child1
comp += child2
comp -= child1
val firstChild = comp(0)

If you want to take this to a logical conclusion, I'd advocate building the whole composite structure as an immutable Directed Acyclic Graph (though I appreciate that this often isn't possible):

case class Composite(children: Component*) extends Component {
  def operation() = children foreach { _.operation() }
}

val comp = Composite(child1, Composite(child2, child3), child4)

Something like

import scala.collection.mutable.ListBuffer

trait Component{
    def operation():Unit
}

class Composite extends Component{

    val children = new ListBuffer[Component]()

    def operation():Unit = children.foreach {_.operation() }

    def add(child: Component):Unit = children += child
    def remove(child: Component):Unit = children -= child
    def getChild(index:Int) = children(index)
 }:

 class Leaf extends Component {
      def operation():Unit = println("leaf") 
 }

This is a very direct translation. Often an immutable solution is preferred in Scala. Another difference is, that you often use pattern matching instead of inheritance. Eg you could rewrite the example by removing operation() from Component and Leaf and writing instead

trait Component{
    def operation():Unit = this match {
      case c:Composite => c.children.foreach(_.operation())
      case leaf:Leaf => println("leaf")  
    }
}

Functionality presented in Java as an interface can be coded in Scala as a trait

trait Component{
    def operation():Unit
}

class Composite extends Component{
    @override
    def operation(){
       for(child<-children)
         child.operation()
    }        

    def add(child:Component){//implementation}
    def remove(child:Component){//implementation}
    def getChild(index:Int){//implementation}
 }

 class Leaf extends Component{
      def operation(){
         //implementation
      }
 }

It's worth saying that traits are more powerful than Java interfaces, and can include implementation as well as interface specifications.

A cleaner immutable way would be:

trait Component {
  def operation()
  def +(other: Component): Component = new Composite(this, other)
}

class Leaf(name: String) extends Component {
  override def operation(): Unit = println(name)
}

class Composite(children: Component*) extends Component {
  override def operation(): Unit = children foreach { _.operation() }
}

val c = new Leaf("Tom") + new Leaf("Tim")
c.operation() // Tom Tim

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM