要約先: Javaの従来の設計パターンから始めて、Scalaの関数型プログラミングの実装を比較します。
キーワード:デザインパターン; Java ; Scala
0動作モード
ビヘイビアモードは、実行時のプログラムの複雑なプロセス制御、つまり、複数のクラスまたはオブジェクトが連携して、単一のオブジェクトだけでは完了できないタスクを完了する方法を説明するために使用されます。これには、アルゴリズムとオブジェクト間の責任の割り当てが含まれます。
動作モデルは、クラス動作モデルとオブジェクト動作モデルに分けられます。前者は継承メカニズムを使用してクラス間で動作を割り当て、後者は組み合わせまたは集約を使用してオブジェクト間で動作を分散します。組み合わせ関係または集約関係は、継承関係よりも結合が少なく、「合成再利用の原則」を満たすため、オブジェクト動作モデルは、クラス動作モデルよりも柔軟性があります。
1戦略モードとテンプレートモード
ストラテジーモードは、その名前が示すように、クラスの動作ストラテジー、またはさまざまなアルゴリズムを使用するストラテジーです。一般的な理解は、状況の変化に応じてさまざまな戦略を選択することです。ハードコードされた(複数の条件付き遷移ステートメント)のブランチ実装と比較して、戦略モードは開始と終了の原則に準拠しています。
ストラテジーモードは、主に、ストラテジーインターフェイス(ストラテジー)、具体的なストラテジー(具体的なストラテジー)、およびストラテジー環境(コンテキスト)の3つの部分で構成されます。写真が示すように。
テンプレートメソッドパターンとは、関数が事前に与えられ、特定のプロセスのロジックがサブクラスによって実装されるプロセスを指します。
2小さなMVCフレームワーク
以下では、小さなMVC Webアーキテクチャを使用します。このアーキテクチャでは、ビュー部分を戦略モードで実装できます。アーキテクチャを図に示します。
3Javaコードの実装
3.1戦略モード
/**
* 用于生成响应体(HttpResponse.body)的接口
*/
public interface View {
String render(Map<String, List<String>> model);
}
/**
* 策略接口
*/
public interface RenderingStrategy {
public String renderView(Map<String, List<String>> model);
}
/**
* 策略模式下的Context类,用于组合不同的策略
*/
public class StrategyView implements View {
/**
* 策略提供的实例
*/
private RenderingStrategy renderingStrategy;
public StrategyView(RenderingStrategy renderingStrategy){
this.renderingStrategy=renderingStrategy;
}
/**
* 使用策略来渲染View
*
* @param model
* @return
*/
@Override
public String render(Map<String, List<String>> model) {
return renderingStrategy.renderView(model);
}
}
RenderingStrategyインターフェイスを実装し、さまざまな実装クラスを使用してStrategyViewクラスをインスタンス化し、さまざまな戦略を使用するだけです。もちろん、StrategyViewで戦略を調整するメソッドを指定することもできます。これにより、コードの柔軟性が向上します。
4Scalaコードの実装
4.1戦略モード
ビューは変更されず、コードは次のとおりです。
trait View {
def render(model:Map[String,List[String]]):String
}
戦略により、次の変更が行われます。
/**
* 用高阶函数来实现函数式接口
* renderingStrategy现在是一个函数变量,用var修饰时,会生成get和set方法,方便动态修改策略。
* 这样,对比于面向对象的接口实现策略,函数式策略更加简单。
* @param renderingStrategy
*/
class StrategyView(var renderingStrategy: Map[String,List[String]] => String) extends View {
override def render(model: Map[String, List[String]]): String = {
renderingStrategy(model)
}
}
これは、機能インターフェイスの変更に相当します。戦略インターフェイスは、オブジェクトの動作、つまり、単一または複数の関数の組み合わせであるため、関数変数を介して戦略インターフェイスを実装できます。
4.2テンプレートメソッドパターンはControllerを実装します
/**
* 控制器接口
* 包含了对HttpRequest的基本处理逻辑
*/
trait Controller {
/**
* 处理request,返回response
* @param request
* @return
*/
def handleRequest(request:HttpRequest):HttpResponse
}
/**
* 模板类,用于代理特定的任务
*
* java实现模板模式,doRequest需要子类来继承,进而实现不同的控制器
*
* scala实现模板模式,用一个函数变量doRequest即可完成,不同的控制器可以由传入的不同函数来实现。
*
* 注意:模板方法模式采用继承来完成工作--类的行为模式,策略方法模式采用组合来完成工作--对象的行为模式
*/
class TemplateController(view: View, doRequest: HttpRequest => Map[String, List[String]]) extends Controller {
/**
* 处理request,返回response
*
* @param request
* @return
*/
override def handleRequest(request: HttpRequest): HttpResponse = {
val resBuilder = HttpResponse.Builder.newBuilder()
try {
val model = doRequest(request)
val body = view.render(model)
resBuilder.body(body)
}catch {
case e:Exception => resBuilder.responseCode(0)
}
resBuilder.build()
}
}
5スカラ
6scalaがWebフレームワークを呼び出す
import tinywbe.HttpRequest
import tinywbe.framework_scala.view.StrategyView
object ExampleScala {
def main(args: Array[String]): Unit = {
val greetingController = new TemplateController(new StrategyView(greetingViewStrategy), doRequest)
val controllers = Map("greetings" -> greetingController)
val filters = List({ x: HttpRequest => println("filter" + 1); x }, { x: HttpRequest => println("filter" + 2); x }, { x: HttpRequest => println("filter" + 3); x })
new TinyWeb(controllers, filters).handleRequest(
HttpRequest.Builder.newBuilder()
.body("12,12,34,56,ff,gg")
.path("greetings")
.build()
).foreach(x => println(x.getBody))
}
//定义控制器与模型层交互的函数
def doRequest(request: HttpRequest): Map[String, List[String]] = {
val path = request.getPath
val data1 = request.getBody
val data2 = data1.split(",").toList.map(name => s"${name} --handle")
Map(path -> data2)
}
//定义View渲染的函数
def greetingViewStrategy(model: Map[String, List[String]]) = {
val sb = new StringBuilder
sb.append("<h1> greeting: </h1>\n")
model("greetings").foreach(line => sb.append(s"<h2> $line </h2>\n"))
sb.toString
}
}
6結論
簡単に言えば、関数型プログラミング言語には、動作パターンの実現に固有の利点があり、関数型インターフェイスを維持する必要がないため、プロジェクト内のコードの量が大幅に削減されます。
オブジェクト指向言語の関数型インターフェース(たとえば、一般的に使用されるコールバックインターフェース)の場合、関数型プログラミングのアイデアが導入されれば、より簡潔になると結論付けることができます。