一些常规问题在Scala中的不同解法

创建单例

 

Singleton (Java)

public class ClassicSingleton {
   private static ClassicSingleton instance = null;
   protected ClassicSingleton() {
      // Exists only to defeat instantiation.
   }
   public static ClassicSingleton getInstance() {
      if(instance == null) {
         instance = new ClassicSingleton();
      }
      return instance;
   }
}

Singleton(Scala)

object ScalaSingleton {
  def printSomething() {
    println("printSomething")
  }
}

被简化掉的东西:

  • 静态私有字段
  • 外界不可访问的constructor
  • 对字段的判空与初始化

声明类

构造函数

属性

Constructor

class ScalaConstructorExample(val x: Double, y: String) {
  println(x + y)
}

Constructor

public class ScalaConstructorExample
{
  private final double x;

  public double x()
  {
    return this.x;
  }

  public ScalaConstructorExample(double x, String y)
  {
    Predef..MODULE$.println(new StringBuilder().append(x).append(y).toString());
  }
}

被简化掉的东西:

  • 声明字段
  • 为只读属性创建getter
  • 为可读写属性创建setter

给两个没有太多关联的继承体系内的两个类消除重复代码

假设已有如下两个继承体系:

abstract class Plant {
  def photosynthesis = println("Oh, the sunlight!")
}

class Rose extends Plant {
  def smell = println("Good!")

  def makePeopleHappy = println("People like me")
}

class Ruderal extends Plant {
  def grow = println("I take up all the space!")
}

abstract class Animal {
  def move = println("I can move!")
}

class Dog extends Animal {
  def bark = println("Woof!")

  def makePeopleHappy = println("People like me")
}

class Snake extends Animal {
  def bite = println("I am poisonous!")
}

常见解决方案1

对继承体系下手,抽取公共父类,将共同行为置于其中。

常见解决方案2

创建一个接口,将共同行为声明于其中。同时提供一个静态方法,来实现共同行为。每一个实现该接口的类,都调用该静态方法。

trait

trait PeoplePleaser {
  def makePeopleHappy = println("People like me")
}

class Rose extends Plant with PeoplePleaser {
  def smell = println("Good!")
}

class Dog extends Animal with PeoplePleaser {
  def bark = println("Woof!")
}

被简化掉的东西:

  • 触碰已有继承体系
  • 将接口和实现分开声明
  • 在每个实现类中调用静态方法

Lazy evaluation

Lazy (Java)

private String str = null;

public String getStr() {
    if (str == null) {
        str = getStrFromWebService();
    }
    return str;
}

Lazy(C#)

private Lazy<String> str = new Lazy<string> (() => GetStrFromWebService ());

public String Str
{
  get
  {
      return str.Value;
  }                    
}

Lazy(Scala)

lazy val str = getStrFromWebService()

被简化掉的东西:

  • 分开声明字段与属性
  • 对字段判空
  • 自己写代码判断web service是否已经被请求过

类型判断,类型转换,取属性,属性值判断

假设已有如下类:

abstract class Animal

case class Cat(name: String) extends Animal

case class Dog(name: String) extends Animal

Java

    Animal animal = createAnimal();
    String result = "other animal";

    if (animal instanceof Dog) {
        result = "this is a dog";
    } else if (animal instanceof Cat) {
        Cat cat = (Cat) animal;
        if (cat.name() == "kitty") {
            result = "this is a cat named kitty";
        }
    }

    return result;

Scala

val animal = createAnimal
animal match {
  case Dog(anyName) => "this is a dog"
  case Cat("kitty") => "this is a cat named kitty"
  case _ => "other animal"
}

被简化掉的东西:

  • 类型判断
  • 类型转换
  • 取属性
  • 属性值判断

Adapter模式

Adapter

class Duck {
  def makeDuckNoise() = "gua gua"
}

class Chicken {
  def makeChickenNoise() = "ge ge"
}
def giveMeADuck(duck: Duck) = duck.makeDuckNoise()

giveMeADuck(new Duck)
class Ducken(chicken: Chicken) extends Duck {
  override def makeDuckNoise() = chicken.makeChickenNoise()
}

giveMeADuck(new Ducken(new Chicken))

Implicit Function

implicit def chickenToDuck(chicken: Chicken) = new Ducken(chicken)

giveMeADuck(new Chicken)

被简化掉的东西:

  • 每次适配都创建适配器实例的代码
  • 嵌套的噪音

先判空,再运算

常规做法

  def calculateTotal: Option[Int] = {
    val price: Option[Int] = getPrice
    val amount: Option[Int] = getAmount

    if (price.isEmpty || amount.isEmpty) {
      None
    } else {
      Some(price.get * amount.get)
    }
  }

简化的做法

  def calculateTotalWithFor: Option[Int] = {
    for (price <- getPrice; amount <- getAmount) yield price * amount
  }

被简化掉的东西:

  • 判断价格是否为空
  • 判断数量是否为空