java 接口 枚举_使用函数接口和枚举实现配置式编程(Java与Scala实现)

概述###

做报表时,有时需要根据不同的业务生成不同的报表。这样,需要能够动态地配置列字段,并根据列字段来输出对应的报表。使用函数接口结合枚举可以比较优雅地实现配置式编程。

问题描述如下:

假设有对象 Student, Teacher ,它们均有属性 Id, Name, Able 。 要求:(1) 打印这些 Student, Teacher 的字段 (Id, Name) 的内容 ; (2) 打印这些 Student, Teacher 的字段 (Name, Able) 的内容。

Java代码示例###

直接上代码。应该能看懂。 需要 Java1.8 才能正常运行。

接口定义####

package zzz.study.function;

/**

* Created by shuqin on 17/3/30.

*/

public interface Person {

String getId();

String getName();

String able();

}

对象定义####

类 Student :

package zzz.study.function;

/**

* Created by shuqin on 17/3/30.

*/

public class Student implements Person {

private String studentId;

private String name;

private String able;

public Student(String studentId, String name, String able) {

this.studentId = studentId;

this.name = name;

this.able = able;

}

@Override

public String getId() {

return studentId;

}

@Override

public String getName() {

return name;

}

@Override

public String able() {

return able;

}

}

类 Teacher :

package zzz.study.function;

/**

* Created by shuqin on 17/3/30.

*/

public class Teacher implements Person {

private String teacherId;

private String name;

private String able;

public Teacher(String teacherId, String name, String able) {

this.teacherId = teacherId;

this.name = name;

this.able = able;

}

@Override

public String getId() {

return teacherId;

}

@Override

public String getName() {

return name;

}

@Override

public String able() {

return able;

}

}

字段定义配置####

字段定义配置是核心。 这里结合了枚举和函数式接口。这里之所以写成 FieldEnum(fieldName, fieldTitle, fieldValueGetMethod) 的定义方式,是为了便于管理。同样可以采用两个 Map 来实现:Map, Map,这样更适用于 Java1.6 , 不过要把两个 Map 拼起来才是完整的字段定义视图。 Person::getName 是方法引用,(Person p) -> p.getName() 的简写形式。

package zzz.study.function;

import java.util.function.Function;

/**

* Created by shuqin on 17/3/30.

*/

public enum FieldConf {

Id("Id", "编号", Person::getId),

Name("Name", "姓名", Person::getName),

Able("Able", "能力", Person::able);

private String name;

private String title;

private Function method;

FieldConf(String name, String title, Function method) {

this.name = name;

this.title = title;

this.method = method;

}

public String getName() {

return name;

}

public String getTitle() {

return title;

}

public Function getMethod() {

return method;

}

}

字段定义伴生类####

FieldConfAccompany 是 FieldConf 的伴生类, 从 Scala 的伴生对象借鉴而来,体现了 类变量、方法 与 实例变量、方法 分离的设计思想,使得两者各司其责, 都比较简洁。

package zzz.study.function;

import java.util.*;

/**

* Created by shuqin on 17/3/30.

* FieldConf 的伴生对象, 从Scala借鉴而来

*/

public class FieldConfAccompany {

private static Map fieldConfMap = new HashMap();

private static List allFields = new ArrayList<>();

static {

for (FieldConf fc: FieldConf.values()) {

fieldConfMap.put(fc.name(), fc);

allFields.add(fc.getName());

}

}

public static FieldConf getInstance(String name) {

return fieldConfMap.get(name);

}

public static List getAllFields() {

return Collections.unmodifiableList(allFields);

}

}

客户端使用####

这里使用了 java8 Stream api 。 并没有什么特别的,只是针对列表的批量流式处理,具备延迟计算特性。

package zzz.study.function;

import java.util.Arrays;

import java.util.List;

import java.util.stream.Collectors;

/**

* Created by shuqin on 17/3/30.

*/

public class Report {

public static void main(String[] args) {

report(Arrays.asList(new String[] {"Id", "Name"}), getPersons());

report(Arrays.asList(new String[] {"Name", "Able"}), getPersons());

}

public static void report(List fields, List persons) {

String reportTitles = fields.stream().map(

field -> FieldConfAccompany.getInstance(field).getTitle()

).collect(Collectors.joining(","));

List rows = persons.stream().map(

p -> fields.stream().map(

field -> FieldConfAccompany.getInstance(field).getMethod().apply(p)

).collect(Collectors.joining(","))

).collect(Collectors.toList());

System.out.println(reportTitles);

System.out.println(String.join("\n",rows));

}

private static List getPersons() {

Person s1 = new Student("s1", "liming", "Study");

Person s2 = new Student("s2", "xueying", "Piano");

Person t1 = new Teacher("t1", "Mr.Q", "Swim");

Person t2 = new Teacher("t2", "Mrs.L", "Dance");

return Arrays.asList(new Person[] {s1, s2, t1, t2});

}

}

输出:

编号,姓名

s1,liming

s2,xueying

t1,Mr.Q

t2,Mrs.L

姓名,能力

liming,Study

xueying,Piano

Mr.Q,Swim

Mrs.L,Dance

Scala代码示例###

业务类####

同样先定义业务类 Person, Student, Teacher 。 可以看到 Scala 的类定义比 Java 类定义的语法形式简洁不少,相当于语言层面实现了 lombok 的功能。

package scalastudy.extend

/**

* Created by shuqin on 17/4/10.

*/

trait Person {

def getId: String

def getName: String

def getAble: String

}

class Student(studentId: String, name:String, able:String) extends Person {

override def getId: String = studentId

override def getName: String = name

override def getAble: String = able

}

class Teacher(teacherId: String, name:String, able:String) extends Person {

override def getId: String = teacherId

override def getName: String = name

override def getAble: String = able

}

字段配置####

Scala 没有直接支持枚举类型,而是提供了 Enumeration 助手类。 可是这个类也不支持定义方法字段,因此,采用样例对象来模拟枚举功能。这里 apply 实现了静态构造器的功能,通过指定名称获取对应的样例对象。Scala 的 Case 功能非常强大,可以匹配常量、变量、容器结构及元素、类对象、正则表达式等各种对象,并赋值给相应的变量。

package scalastudy.extend

/**

* Created by shuqin on 17/4/10.

* Scala 实现枚举; 由于 Enumeration 不支持枚举含有方法字段,因此采用样例对象模拟实现。

*/

sealed class FieldConf(name:String, title:String, able: (Person)=>String) {

def getTitle = title

def getAble = able

}

object FieldConf {

def apply(name: String): FieldConf = {

name match {

case "Id" => Id

case "Name" => Name

case "Able" => Able

case _ => Unknown

}

}

}

case object Id extends FieldConf("Id", "编号", p => p.getId)

case object Name extends FieldConf("Name", "姓名", p => p.getName)

case object Able extends FieldConf("Able", "能力", p => p.getAble)

case object Unknown extends FieldConf("Unknown", "未知", p => "")

报表输出####

Scala 提供了相当多的助手方法,可以方便地实现常用功能,比如对列表拼接字符串。 在 Java 中就要难受地一次次编写无聊的 new StringBuilder , append, return sb.toString 这种套话, 而在 Scala 只要使用 mkString 即可,类似于 Python 的 join 方法。 Scala 的 lambda 表达式也很简洁,如果只有单变量的话,不必显式写出 p => doFor(p) 的形式, 而是直接可写成 doFor(_) 。

package scalastudy.extend

/**

* Created by shuqin on 17/4/10.

*/

object ExtendedReport extends App {

launch()

def launch(): Unit = {

report(List("Id", "Name"), getPersons())

report(List("Name", "Able"), getPersons())

}

def report(fields:List[String], persons:List[Person]):Unit = {

val titles = fields.map(FieldConf(_).getTitle).mkString(",")

println(titles)

val rows = persons.map(

p => fields.map(FieldConf(_).getAble.apply(p)).mkString(",")

).mkString("\n")

println(rows)

}

def getPersons():List[Person] = {

List(new Student("s1", "liming", "Study"), new Student("s2", "xueying", "Piano"),

new Teacher("t1", "Mr.Q", "Swim"), new Teacher("t2", "Mrs.L", "Dance"))

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值