Spark小课堂Week7

从Spark中一个例子看面向对象设计

今天我们讨论了个问题,来设计一个Spark中的常用功能。

功能描述:数据源是一切处理的源头,这次要实现下加载数据源的方法load()

初始需求

需求:支持Json数据源加载

具体:输入一个path,需要返回一个Relation,

Relation中提供scan()和write()两个方法

示意代码:

class Context{
public Relation json(String path){
return new Relation(path);
}
} class Relation{
public Relation(path);
public scan();
public write();
}

第一次需求变化

现在需要添加jdbc数据源,输入的是url和tableName,需要有自己的Relation实现

简单实现:

class Context{
public JsonRelation json(String path){
return new JsonRelation(path);
}
public JdbcRelation jdbc(String url,String tableName){
return new JdbcRelation(url,tableName);
}
} class JsonRelation{
public JsonRelation(String path);
public scan();
public write();
}
class JdbcRelation{
public JdbcRelation(String url,String tableName);
public scan();
public write();
}

这个实现明显违反了开放封闭原则,增加一种文件格式,需要对核心类Context进行修改!!!

方法整合

所以首先,需要对json和jdbc方法进行合并为format,参数也进行合并,

source参数表示数据源,是一个字符串,比如:"json"、"jdbc"

逻辑整合起来

class Context{
public Relation format(String source,Map param){
if(source == "json") return new JsonRelation(param.get("path"));
if(source == "jdbc") return new JdbcRelation(param.get("url"),param.get("tableName"));
...
}
} class JsonRelation extends Relation{
public JsonRelation(String path);
public scan();
public write();
}
class JdbcRelation extends Relation{
public JdbcRelation(String url,String tableName);
public scan();
public write();
}

方法通用化。

format方法还是违反了开放封闭原则。我们可以使用反射对其进行通用化。

class Context{
public Relation format(String source,Map param){
Class c = Class.forName(source + "Relation");
Constructor constructor= c.getDeclaredConstructor(Map.class);
return constructor.newInstance(param);
...
}
}
class JsonRelation extends Relation{
public JsonRelation(Map param){
this.path = param.get("path");
};
public scan();
public write();
}
class JdbcRelation extends Relation{
public JdbcRelation(Map param){
this.url = param.get("url");
this.tableName = param.get("tableName");
}
public scan();
public write();
}

第二次需求变化

需求:再增加一种文件类型csv,同样是输入path

按照之前的思路,我们可以增加一个Relation类

class CsvRelation extends Relation{
public CsvRelation(Map param){
this.path = param.get("path");
};
public scan();
public write();
}

这里有一个问题,我们其发现构造方法和JsonRelation是完全重复的,有没有办法消除这种重复

消除重复,第一点是需要把重复的部分拆离出来。我们把Relation类拆分为Relation类和Provider类。其中Provider是一个工厂方法,通过反射来调用。

class Context{
public Relation format(String source,Map param){
Class c = Class.forName(source + "Provider");
Method method= c.getMethod("getRelation",Map.class);
return method.invoke(null,param);
...
}
}
class JsonProvider{
public static createRelation(Param param){
return new JSonRelation(param.get("path"));
};
}
class JsonRelation extends Relation{
public JsonRelation(String path);
public scan();
public write();
}
class CsvProvider{
public static createRelation(Param param){
return new CsvRelation(param.get("path"));
};
}
class CsvRelation extends Relation{
public CsvRelation(String path);
public scan();
public write();
}
class JdbcProvider{
public static Relation createRelation(Param param){
return new JdbcRelation(param.get("url"),param.get("tableName"));
};
}
class JdbcRelation extends Relation{
public JdbcRelation(String path,String tableName);
public scan();
public write();
}

Json和csv采用path构造,而jdbc使用url+table,这个可以认为是一个固有的规则,我们可以把构造中间重复的逻辑再单独抽取出来

class Context{
public Relation format(String source,Map param){
Class c = Class.forName(source + "Provider");
if(hasIntereface(c,PathProvider.class)){
Method method= c.getMethod("getRelation",String.class);
return method.invoke(null,param.get("path"));
}
if(hasIntereface(c,UrlProvider.class)){
Method method= c.getMethod("getRelation",String.class,String.class);
return method.invoke(null,param.get("url"),param.get("tableName"));
}
...
}
}
class JsonProvider implements PathProvider{
public static createRelation(String path){
return new JSonRelation(path);
};
}
class CsvProvider implements PathProvider{
public static createRelation(String path){
return new CsvRelation(path);
};
}
class JdbcProvider implements UrlProvider{
public static Relation createRelation(String url,String tableName){
return new JdbcRelation(url,tableName);
};
}

然后,我们发现format方法中的实现有些太复杂,所以单独抽取出来

class Context{
public Relation format(String source,Map param){
return Provider.getRelation(source,param);
}
}
class Provider{
public Relation getRelation(String source,Param,param){
Class c = Class.forName(source + "Provider");
if(hasIntereface(c,PathProvider.class)){
Method method= c.getMethod("getRelation",String.class);
return method.invoke(null,param.get("path"));
}
if(hasIntereface(c,UrlProvider.class)){
Method method= c.getMethod("getRelation",String.class,String.class);
return method.invoke(null,param.get("url"),param.get("tableName"));
}
...
}
}

小结

未完待续。

这个例子主要是进行对象的构造,是比较有通用性的。

我们可以看到,面向对象设计中,主要是靠不同对象的特性来实现变化。

而对于对象的构造会需要一些规则来驱动,这种规则我们一般抽象为接口来标识,

处理这些规则的往往都是工厂方法,也是工厂的一个非常重要的作用。

Spark小课堂Week7 从Spark中一个例子看面向对象设计的更多相关文章

  1. Spark小课堂Week1 Hello Spark

    Spark小课堂Week1 Hello Spark 看到Spark这个词,你的第一印象是什么? 这是一朵"火花",官方的定义是Spark是一个高速的.通用的.分布式计算系统!!! ...

  2. Spark小课堂Week6 启动日志详解

    Spark小课堂Week6 启动日志详解 作为分布式系统,Spark程序是非常难以使用传统方法来进行调试的,所以我们主要的武器是日志,今天会对启动日志进行一下详解. 日志详解 今天主要遍历下Strea ...

  3. Spark小课堂Week5 Scala初探

    Spark小课堂Week5 Scala初探 Scala是java威力加强版. 对Java的改进 这里会结合StreamingContext.scala这个代码说明下对Java的改进方面. 方便测试方式 ...

  4. Spark小课堂Week4 从控制台看Spark逻辑结构

    Spark小课堂Week4 从控制台看Spark逻辑结构 层级关系: 从监控控制台,我们可以看到如下关系: 一个 Job 包含 n Stage 一个 Stage 包含 n Task Job0解决什么问 ...

  5. Spark小课堂Week3 FirstSparkApp(Dataframe开发)

    Spark小课堂Week3 FirstSparkApp(代码优化) RDD代码简化 对于昨天练习的代码,我们可以从几个方面来简化: 使用fluent风格写法,可以减少对于中间变量的定义. 使用lamb ...

  6. Spark小课堂Week3 FirstSparkApp(RDD开发)

    Spark小课堂Week3 FirstSparkApp 问题:Java有哪些数据结构 大致有如下几种,其中List与Map是最重要的: List Map Set Array Heap Stack Qu ...

  7. Spark小课堂Week2 Hello Streaming

    Spark小课堂Week2 Hello Streaming 我们是怎么进行数据处理的? 批量方式处理 目前最常采用的是批量方式处理,指非工作时间运行,定时或者事件触发.这种方式的好处是逻辑简单,不影响 ...

  8. (转载)小课堂UI-有关配色的一个小技巧

  9. PJzhang:安全小课堂-安全软件为什么很重要,看这里!

    猫宁!!! 参考链接: http://www.360.cn/webzhuanti/mianyigongju.html https://www.freebuf.com/fevents/204100.ht ...

随机推荐

  1. c实例_挑战程序竞赛,蚂蚁

    #include <stdio.h> //蚂蚁的题目 int max(int a,int b) { int count; count=a>b?a:b; return count; } ...

  2. python 实现接口测试

    接口的类型有很多,但是我们经常遇见经常用的就get和post两种.这两种有什么区别呢?个人理解主要是表现在安全性方面. Python代码POST任意的HTTP数据以及使用Cookie的方法,有需要的朋 ...

  3. [iOS 10 day by day] Day 1:开发 iMessage 的第三方插件

    本文介绍了 iOS 10 的一个重要更新:Messages 应用支持第三方插件了.作者用一个小游戏作为例子,说明了插件开发从建工程开始,到绘制界面.收发消息的全过程. <iOS 10 day b ...

  4. Pretty Poem

    Poetry is a form of literature that uses aesthetic and rhythmic qualities of language. There are man ...

  5. The Romantic Hero

    Problem Description There is an old country and the king fell in love with a devil. The devil always ...

  6. Jedis操作Redis数据库

    添加Maven依赖: <dependencies> <!-- 单元测试 --> <dependency> <groupId>junit</grou ...

  7. HTML5与CSS3基础教程第八版学习笔记11~15章

    第十一章,用CSS进行布局 开始布局注意事项 1.内容与显示分离 2.布局方法:固定宽度和响应式布局 固定宽度,整个页面和每一栏都有基于像素的宽度 响应式布局也称为流式页面,使用百分数定义宽度 3.浏 ...

  8. HttpClient(4.3.5) - HTTP Header

    An HTTP message can contain a number of headers describing properties of the message such as the con ...

  9. Lombok(1.14.8) - @NoArgsConstructor, @RequiredArgsConstructor & @AllArgsConstructor

    @NoArgsConstructor @NoArgsConstructor,提供一个无参的构造方法. package com.huey.hello.bean; import java.util.Dat ...

  10. django 学习-5 模板使用流程

    首先在模板下建一个index.html <!DOCTYPE html><html><head><meta charset="utf-8" ...