欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java编程基础(2)| 春松客服

程序员文章站 2022-05-19 20:55:42
...

1. 示例代码

上次一我们谈到Java的基本数据类型和语法,今天我们聊聊Java的反射和切面编程,面向对象编程,Java设计模式。
A set of examples to learning Java. 链接:https://github.com/Samurais/java-get-started
java-get-started 示例

  • 基本数据类型
  • 控制流
  • 异常处理
  • 反射
  • 切面编程
  • 面向对象编程
  • Java 8 新特性

2. 反射和切面编程

为什么要面向切面编程

  1. 面向切面编程使得每个关注点都集中于一个地方而不是分散在多处代码中,便于后期的统一维护管理。
  2. 服务模块更简洁,它们只包含主要关注点,而次要关注点的代码被转移到切面中了。
  3. 对原方法进行方法增强,且不影响原方法的正常使用。
  4. 使用简单可插拔的配置,在实际逻辑执行之前、之后或周围动态添加横切关注点。
  5. 切面的内容可以复用,比如TimeHandler的printTime方法,任何地方需要打印方法执行前的时间与方法执行后的时间,都可以使用TimeHandler的printTime方法。
  6. 避免使用Proxy、CGLIB生成代理,这方面的工作全部框架去实现,开发者可以专注于切面内容本身。

什么是反射

反射是Java编程语言中的功能。它允许执行中的Java程序自行检查或“理解”并操纵程序的内部属性。例如,Java类可以获取其所有成员的名称并显示它们。
Java 反射机制在程序运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。这种 动态的获取信息 以及 动态调用对象的方法 的功能称为 java 的反射机制。

切面编程示例

AOP(Aspect Oriented Programming)中文翻译为面向切面编程,是指通过预编译方式和运行期动态代理实现程序中某些功能的统一维护的一种技术。

  • AspectJ
    AspectJ是一个面向切面的框架,它扩展了Java语言。 AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
    Java编程基础(2)| 春松客服
    例子
    Java编程基础(2)| 春松客服
    AspectJ示例代码1:
package com.chatopera.tutorials.java.aop;

public class Sample {

    public static void sayHello() {
        System.out.println("Hello");
    }

    public static void greeting() {

        String name = new String("John");

        sayHello();

        System.out.print(name);
    }

    public static void main(String[] args) {

        sayHello();

        System.out.println("--------");

        sayHello();

        System.out.println("--------");

        greeting();
    }
}

没有使用切面编程运行结果
Java编程基础(2)| 春松客服
使用AspectJ编译
需要先安装AspectJ
运行文件代码:

# constants
baseDir=$(cd `dirname "$0"`;pwd)
rootDir=$(cd $baseDir/../../../../../../../../..;pwd)
export PATH=$PATH:$rootDir/tools/bin

# export PATH=$PATH:~/java/aspect/bin
PKG_NAME=com.chatopera.tutorials.java.aop
CLASSPATH_EXT="$rootDir/app/src/main/java:$rootDir/tools/lib/aspectjrt.jar:$rootDir/tools/lib/aspectjtools.jar:$rootDir/tools/lib/aspectjweaver.jar"
CLASS_NAME=com.chatopera.tutorials.java.aop.Sample

# functions

# main
[ -z "${BASH_SOURCE[0]}" -o "${BASH_SOURCE[0]}" = "$0" ] || return
cd $baseDir
echo $CLASSPATH_EXT
set -x
mv HelloAspectJ.ja HelloAspectJ.java
ajc -classpath "$CLASSPATH_EXT" *.java
mv HelloAspectJ.java HelloAspectJ.ja

if [ $? -eq 0 ]; then
    echo "Compiled successfully."
    java -ea -classpath "$CLASSPATH_EXT" $CLASS_NAME
else
    echo "Error happens."
    exit $?
fi

HelloAspectJ.ja文件


package com.chatopera.tutorials.java.aop;

public aspect HelloAspectJ {

    // Define a Pointcut is
    // collection of JoinPoint call sayHello of class HelloAspectJDemo.
    pointcut callSayHello(): call(* Sample.sayHello());

    before() : callSayHello() {
        System.out.println("Before call sayHello");
    }

    after() : callSayHello()  {
        System.out.println("After call sayHello");
    }


}

再次运行结果
Java编程基础(2)| 春松客服

AspectJ示例代码2:
Secured.java注解

package com.chatopera.tutorials.java.aspectj;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Secured {
    public boolean isLocked() default false;
}

SecuredMethod.java文件使用注解

package com.chatopera.tutorials.java.aspectj;

/**
 * 封装两个方法:通过切面控制是否执行
 */
public class SecuredMethod {

    /**
     * 不允许调用
     */
    @Secured(isLocked = true)
    public void lockedMethod() {
        System.out.println("I am locked method, actually I was never called.");
    }

    /**
     * 允许调用
     */
    @Secured(isLocked = false)
    public void unlockedMethod() {
        System.out.println("I am unlocked method, call me whenever you want.");
    }
}

SecuredMethodAspect.java文件实现注解

package com.chatopera.tutorials.java.aspectj;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class SecuredMethodAspect {
    @Pointcut("execution(* *(..)) && @annotation(secured)") //关注的时间点
    public void callAt(Secured secured) {
    }

    @Around("callAt(secured)")
    public Object around(   //around表示前和后
            ProceedingJoinPoint pjp,
            Secured secured) throws Throwable {
        System.out.println(pjp.getSignature().getName() + " isLocked: " + secured.isLocked());

        if (secured.isLocked()) {
            return null;
        } else {
            return pjp.proceed();
        }
    }
}

执行结果
Java编程基础(2)| 春松客服
从执行结果可以看出调用了unlockedMethod方法。

总结反射的优点

  1. 反射提高了Java程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需提高硬编码目标类
  2. 代码简洁,提高代码的复用率,外部调用方便。
  3. 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法。
  4. 反射是其他一些常用语言,如C、C++、Fortran或者Pascal等不具备的。
  5. Java反射技术应用领域很广,如软件测试、JavaBean等。
  6. 许多流行的开源框架例如Struts、Hibernate、Spring在实现过程中都采用了该技术。

3. 面向对象编程

抽象(Abstraction)

抽象向用户隐藏了复杂性,仅显示相关信息。每个类分别实现抽象方法的细节。
Java编程基础(2)| 春松客服

封装(Encapsulation)

封装将数据及其相关方法绑定到一个类中。它还通过将字段设为私有并仅通过其相关方法来访问它们来保护数据。
Java编程基础(2)| 春松客服

继承(Inheritance)

继承允许一个类(子类)继承另一个类(父类)的功能(字段和方法)。在Java中,一个类只能扩展另一个类。
Java编程基础(2)| 春松客服

多态(Polymorphism)

多态性使得可以以不同的形式使用相同的代码结构。如果Java类的参数结构不同,则它们可以具有各种相同的方法。
Java编程基础(2)| 春松客服

  • 示例代码
    Java 设计鸟类Bird, 鱼类Fish ,都继承自抽象的动物类AbstractAnimal,使用java面向对象创建动物类并输出动物信息。
    AbstractAnimal.java
package com.chatopera.tutorials.java.oo;

abstract public class AbstractAnimal implements IAnimal {

    private int numberOfLegs;

    // abstract methods
    public void move() {
        System.out.println(this.getClass().getName() + " :move UNKNOWN.");
    }

    public void eat() {
        System.out.println(this.getClass().getName() + " :eat UNKNOWN.");
    }

    public void requisite() {
        System.out.println(this.getClass().getName() + " requisite: water, oxygen.");
    }

    // concrete method
    abstract void label();

    public int getNumberOfLegs() {
        return numberOfLegs;
    }

    public void setNumberOfLegs(int numberOfLegs) {
        this.numberOfLegs = numberOfLegs;
    }
}

Bird.java

package com.chatopera.tutorials.java.oo;

public class Bird extends AbstractAnimal {

    public Bird() {
        super();
        this.setNumberOfLegs(2);
    }

    @Override
    public void move() {
        System.out.println(this.getClass().getName() + " move: Moves by flying.");
    }

    @Override
    public void eat() {
        System.out.println(this.getClass().getName() + " eat: Eats birdfood.");
    }

    @Override
    void label() {

    }
}

Fish.java

package com.chatopera.tutorials.java.oo;

public class Fish extends AbstractAnimal {

    @Override
    public void move() {
        System.out.println(this.getClass().getName() + " move: Moves by swimming.");
    }

    @Override
    public void eat() {
        System.out.println(this.getClass().getName() + " eat: Eats seafood.");
    }

    @Override
    void label() {
        System.out.println(this.getClass().getName() + " label");

    }
}

执行BirdTest.java结果
Java编程基础(2)| 春松客服

4. Java设计模式

设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理地运用设计模式可以完美地解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式都描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是设计模式能被广泛应用的原因。
Java编程基础(2)| 春松客服

  • 洋葱模型
Composer composer = new Composer<SampleContext>(); 
composer.use(new Mw1()); 
composer.use(new Mw2()); 
SampleContext context = new SampleContext(); 
composer.handle(context); 
print(context.getData());

Java编程基础(2)| 春松客服

  • 洋葱模型示例代码

package com.chatopera.tutorials.java.designpattern;

import com.chatopera.compose4j.AbstractContext;
import com.chatopera.compose4j.Composer;
import com.chatopera.compose4j.Functional;
import com.chatopera.compose4j.Middleware;
import com.chatopera.compose4j.exception.Compose4jRuntimeException;

import java.util.HashMap;

public class OnionPattern {

    private static final String VAL1 = "what's up";

    protected static void print(final HashMap<String, String> map) {
        if (map != null) {
            System.out.println("   [print] object items size " + map.size());

            for (final String key : map.keySet()) {
                System.out.println("   [print] key " + key + " , value " + map.get(key));
            }
        } else {
            System.out.println("   [print] object is null.");
        }
    }

    public static class SampleContext extends AbstractContext {
        private HashMap<String, String> data = new HashMap<>();

        public HashMap<String, String> getData() {
            return data;
        }

        public void setData(HashMap<String, String> data) {
            this.data = data;
        }
    }

    static class Mw1 implements Middleware<SampleContext> {
        @Override
        public void apply(final SampleContext ctx, final Functional next) {
            System.out.println("[Mw1] apply 1");

            ctx.getData().put("foo", "bar");
            ctx.getData().put("foo2", "bar2");
            print(ctx.getData());
            next.apply();
            System.out.println("[Mw1] apply 2");

            print(ctx.getData());
        }
    }


    static class Mw2 implements Middleware<SampleContext> {

        @Override
        public void apply(final SampleContext ctx, final Functional next) {
            System.out.println("[Mw2] apply 1");
            ctx.getData().put("foo", VAL1);
            ctx.getData().put("foo3", "another item");
            print(ctx.getData());
            next.apply();
            System.out.println("[Mw2] apply 2");
            print(ctx.getData());
        }
    }

    public static void main(String[] args) throws Compose4jRuntimeException {
        Composer composer = new Composer<SampleContext>();
        composer.use(new Mw1());
        composer.use(new Mw2());

        SampleContext context = new SampleContext();
        composer.handle(context);

        System.out.println("[testCompose] result");
        print(context.getData());
    }

}

执行结果
Java编程基础(2)| 春松客服
Java编程基础(2)| 春松客服

  • 单例模式
    单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
    这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
    注意:
    1、单例类只能有一个实例。
    2、单例类必须自己创建自己的唯一实例。
    3、单例类必须给所有其他对象提供这一实例。

示例代码

package com.chatopera.tutorials.java.designpattern;

/**
 * 单体模式
 */
public class SingletonPattern {
    private static SingletonPattern SINGLE_INSTANCE = null;

    private SingletonPattern() {
    }

    public static SingletonPattern getInstance() {
        if (SINGLE_INSTANCE == null) {
            synchronized (SingletonPattern.class) {
                SINGLE_INSTANCE = new SingletonPattern();
            }
        }
        return SINGLE_INSTANCE;
    }
}

5. 推荐书籍

Hrdcore Java 轻快的Java 程序员的自我修养
Java编程基础(2)| 春松客服 Java编程基础(2)| 春松客服 Java编程基础(2)| 春松客服

6. 延伸阅读

春松客服部署方案
春松客服RestAPI
春松客服开发环境

开源智能客服系统

春松客服是 Chatopera 自主研发的,Apache2.0开源协议授权的智能客服系统,企业可以免费使用。春松客服会不断增强客服系统的智能化,这包括利用自然语言处理、机器学习和语音识别等技术让客服工作更有效率、客服满意度更高、成本更低。

Java编程基础(2)| 春松客服