/** Logic to process some user input. */
interface Command {
/**
* String token that signifies this command should be selected (e.g.:
* "deposit", "withdraw")
*/
String key();
/** Process the rest of the command's words and do something. */
Result handleInput(List input);
/**
* This wrapper class is introduced to make a future change easier
* even though it looks unnecessary right now.
*/
final class Result {
private final Status status;
private Result(Status status) {
this.status = status;
}
static Result invalid() {
return new Result(Status.INVALID);
}
static Result handled() {
return new Result(Status.HANDLED);
}
Status status() {
return status;
}
}
enum Status {
INVALID,
HANDLED
}
}
指令路由器
创建CommandRouter记录ATM可以处理的所有指令,并将指令交给具体的实现类进行处理。
final class CommandRouter {
private final Map commands = new HashMap<>();
Result route(String input) {
List splitInput = split(input);
if (splitInput.isEmpty()) {
return invalidCommand(input);
}
String commandKey = splitInput.get(0);
Command command = commands.get(commandKey);
if (command == null) {
return invalidCommand(input);
}
List args = splitInput.subList(1, splitInput.size());
Result result = command.handleInput(args);
return result.status().equals(Status.INVALID) ?
invalidCommand(input) : result;
}
private Result invalidCommand(String input) {
System.out.println(
String.format("couldn't understand \"%s\". please try again.", input));
return Result.invalid();
}
// Split on whitespace
private static List split(String input) {
return Arrays.asList(input.trim().split("\\s+"));
}
}
创建Main
创建Main函数实现上述类的交互。
class CommandLineAtm {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
CommandRouter commandRouter = new CommandRouter();
while (scanner.hasNextLine()) {
Command.Result unused = commandRouter.route(scanner.nextLine());
}
}
}
E:\IdeaProjects\DeaggerDemo\Dagger2ATMApp\src\main\java\dagger\example\atm\CommandRouterFactory.java:6
java: [Dagger/MissingBinding] dagger.example.atm.CommandRouter cannot be provided without an @Inject constructor or an @Provides-annotated method.
dagger.example.atm.CommandRouter is requested at
dagger.example.atm.CommandRouterFactory.router()
final class HelloWorldCommand implements Command {
@Inject
HelloWorldCommand() {
}
@Override
public String key() {
return "hello";
}
@Override
public Result handleInput(List input) {
if (!input.isEmpty()) {
return Result.invalid();
}
System.out.println("world!");
return Result.handled();
}
}
将HelloWorldCommand添加到CommandRouter
final class CommandRouter {
private final Map commands = new HashMap<>();
@Inject
CommandRouter(HelloWorldCommand helloWorldCommand) {
commands.put(helloWorldCommand.key(), helloWorldCommand);
}
...
}
E:\IdeaProjects\DeaggerDemo\Dagger2ATMApp\src\main\java\dagger\example\atm\CommandRouterFactory.java:6
java: [Dagger/MissingBinding] dagger.example.atm.Command cannot be provided without an @Provides-annotated method.
dagger.example.atm.Command is injected at
dagger.example.atm.CommandRouter(command)
dagger.example.atm.CommandRouter is requested at
dagger.example.atm.CommandRouterFactory.router()
private final Outputter outputter;
@Inject
HelloWorldCommand(Outputter outputter) {
this.outputter = outputter;
}
...
@Override
public Result handleInput(List input) {
if (!input.isEmpty()) {
return Result.invalid();
}
outputter.output("world!");
return Result.handled();
}
提供Outputter
通过前面我们可以知道,对于接口的注入需要进行下面三个步骤:
创建被@Inject修饰构造函数的实现类
public class SystemOutOutputter implements Outputter{
@Inject
public SystemOutOutputter(){
}
@Override
public void output(String output) {
System.out.println(output);
}
}
创建使用接口说明的@Module、@Binds函数
@Module
public abstract class OutputterModule {
@Binds
abstract Outputter getOutputer(SystemOutOutputter outputter);
}
/** Abstract command that accepts a single argument. */
abstract class SingleArgCommand implements Command {
@Override
public final Result handleInput(List input) {
return input.size() == 1 ? handleArg(input.get(0)) : Result.invalid();
}
/** Handles the single argument to the command. */
protected abstract Result handleArg(String arg);
}
创建登录指令类LoginCommand
final class LoginCommand extends SingleArgCommand {
private final Outputter outputter;
@Inject
LoginCommand(Outputter outputter) {
this.outputter = outputter;
}
@Override
public String key() {
return "login";
}
@Override
public Result handleArg(String username) {
outputter.output(username + " is logged in.");
return Result.handled();
}
}
E:\IdeaProjects\DeaggerDemo\Dagger2ATMApp\src\main\java\dagger\example\atm\CommandRouterFactory.java:6
java: [Dagger/DuplicateBindings] dagger.example.atm.Command is bound multiple times:
@Binds dagger.example.atm.Command dagger.example.atm.HelloWorldModule.helloWorldCommand(dagger.example.atm.HelloWorldCommand)
@Binds dagger.example.atm.Command dagger.example.atm.LoginCommandModule.loginCommand(dagger.example.atm.LoginCommand)
dagger.example.atm.Command is injected at
dagger.example.atm.CommandRouter(command)
dagger.example.atm.CommandRouter is requested at
dagger.example.atm.CommandRouterFactory.router()
deposit gch 2
gch now has: 2
login gch
gch is logged in with balance: 0
明明刚存入2,怎么登录显示余额0? 为了让情况更明显一些,在Database、LoginCommand、DepositCommand构造函数添加System.out.println("Creating a new " + this);,为了让打印更清晰,在LoginCommand、DepositCommand构造函数再添加System.out.println("database:" + database);
对项目进行编译 Build->Rebuild Project Run
Creating a new org.Database@71e7a66b
Creating a new org.LoginCommand@246ae04d
database:org.Database@71e7a66b
Creating a new org.Database@2ef9b8bc
Creating a new org.DepositCommand@5d624da6
database:org.Database@2ef9b8bc
@Singleton
final class Database { ... }
@Singleton
@Component
interface CommandRouterFactory {
...
}
对项目进行编译 Build->Rebuild Project Run
Creating a new org.Database@591f989e
Creating a new org.LoginCommand@4cb2c100
database:org.Database@591f989e
Creating a new org.DepositCommand@77b52d12
database:org.Database@591f989e
@Singleton
final class CommandProcessor {
private final Deque commandRouterStack = new ArrayDeque<>();
@Inject
CommandProcessor(CommandRouter firstCommandRouter) {
commandRouterStack.push(firstCommandRouter);
}
Command.Status process(String input) {
Command.Result result = commandRouterStack.peek().route(input);
if (result.status().equals(Command.Status.INPUT_COMPLETED)) {
commandRouterStack.pop();
return commandRouterStack.isEmpty()
? Command.Status.INPUT_COMPLETED : Command.Status.HANDLED;
}
result.nestedCommandRouter().ifPresent(commandRouterStack::push);
return result.status();
}
}
调整Command
interface Command {
/**
* Process the rest of the command's words and do something.
*/
Result handleInput(List input);
/**
* This wrapper class is introduced to make a future change easier
* even though it looks unnecessary right now.
*/
final class Result {
private final Status status;
private final Optional nestedCommandRouter;
private Result(Status status, Optional nestedCommandRouter) {
this.status = status;
this.nestedCommandRouter = nestedCommandRouter;
}
static Result invalid() {
return new Result(Status.INVALID, Optional.empty());
}
static Result handled() {
return new Result(Status.HANDLED, Optional.empty());
}
Status status() {
return status;
}
public Optional nestedCommandRouter() {
return nestedCommandRouter;
}
static Result enterNestedCommandSet(CommandRouter nestedCommandRouter) {
return new Result(Status.HANDLED, Optional.of(nestedCommandRouter));
}
}
enum Status {
INVALID,
HANDLED,
INPUT_COMPLETED
}
}
final class WithdrawCommand extends BigDecimalCommand {
private final Database.Account account;
private final Outputter outputter;
private final BigDecimal minimumBalance;
private final BigDecimal maximumWithdrawal;
@Inject
WithdrawCommand(Database.Account account, Outputter outputter, BigDecimal minimumBalance,
BigDecimal maximumWithdrawal) {
super(outputter);
this.account = account;
this.outputter = outputter;
this.minimumBalance = minimumBalance;
this.maximumWithdrawal = maximumWithdrawal;
}
@Override
protected void handleAmount(BigDecimal amount) {
if (amount.compareTo(maximumWithdrawal) > 0) {
outputter.output("超过单次最大提取额度");
return;
}
BigDecimal newBalance = account.balance().subtract(amount);
if (newBalance.compareTo(minimumBalance) < 0) {
outputter.output("超过最低余额限制");
return;
}
account.withdraw(amount);
outputter.output(account.username() + " new balance is: " + account.balance());
}
}
对项目进行编译 Build->Rebuild Project
E:\IdeaProjects\DeaggerDemo\Dagger2ATMApp\src\main\java\dagger\example\atm\CommandProcessorFactory.java:10
java: [Dagger/DuplicateBindings] java.math.BigDecimal is bound multiple times:
@Provides java.math.BigDecimal dagger.example.atm.AmountsModule.maximumWithdrawal()
@Provides java.math.BigDecimal dagger.example.atm.AmountsModule.minimumBalance()
java.math.BigDecimal is injected at
dagger.example.atm.WithdrawCommand(…, maximumWithdrawal)
dagger.example.atm.WithdrawCommand is injected at
dagger.example.atm.UserCommandsModule.withdrawCommand(command)
java.util.Map is injected at
dagger.example.atm.CommandRouter(map)
dagger.example.atm.CommandRouter is requested at
dagger.example.atm.UserCommandsRouter.router() [dagger.example.atm.CommandProcessorFactory → dagger.example.atm.UserCommandsRouter]
It is also requested at:
dagger.example.atm.WithdrawCommand(…, minimumBalance, …)
final class WithdrawCommand extends BigDecimalCommand {
@Inject
WithdrawCommand(Database.Account account, Outputter outputter,
@MinimumBalance BigDecimal minimumBalance,
@MaximumWithdrawal BigDecimal maximumWithdrawal) {
...
对项目进行编译 Build->Rebuild Project现在就可以了。 稍微进行测试一下
login gch
gch is logged in with balance: 0
withdraw 100
超过最低余额限制
deposit 10000
gch now has: 10000
withdraw 2000
超过单次最大提取额度
withdraw 1000
gch new balance is: 9000
login gch
gch is logged in with balance: 0
DepositCommand.withdrawalLimiter:org.WithdrawalLimiter@5056dfcb
WithdrawCommand.withdrawalLimiter:org.WithdrawalLimiter@2344fc66
E:\IdeaProjects\DeaggerDemo\Dagger2ATMApp\src\main\java\dagger\example\atm\CommandProcessorFactory.java:9
java: [dagger.example.atm.UserCommandsRouter] dagger.example.atm.UserCommandsRouter has conflicting scopes:
dagger.example.atm.CommandProcessorFactory also has @Singleton
@Singleton的源码如下:
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Singleton {
}
login gch
gch is logged in with balance: 0
deposit 10000
gch now has: 10000
withdraw 2000
gch new balance is: 8000
withdraw 2000
gch new balance is: 6000
logout
退出登录成功
login gch
gch is logged in with balance: 6000
withdraw 600
gch new balance is: 5400
withdraw 500
超过Session最大提取额度
login gch
gch is logged in with balance: 0
login abc
当前已处于登录状态,退出登录前不能进行登录
couldn't understand "login abc". please try again.
logout
退出登录成功
login abc
abc is logged in with balance: 0
Context Bound,上下文界定,是Scala为隐式参数引入的一种语法糖,使得隐式转换的编码更加简洁。
隐式参数
首先引入一个泛型函数max,用于取a和b的最大值
def max[T](a: T, b: T) = {
if (a > b) a else b
}
因为T是未知类型,只有运行时才会代入真正的类型,因此调用a >
最近用到企业通讯录,虽然以前也开发过,但是用的是jsf,拼成的树形,及其笨重和难维护。后来就想到直接生成json格式字符串,页面上也好展现。
// 首先取出每个部门的联系人
for (int i = 0; i < depList.size(); i++) {
List<Contacts> list = getContactList(depList.get(i
servlet3.0以后支持异步处理请求,具体是使用AsyncContext ,包装httpservletRequest以及httpservletResponse具有异步的功能,
final AsyncContext ac = request.startAsync(request, response);
ac.s
甲说:
A B两个表总数据量都很大,在百万以上。
idx1 idx2字段表示是索引字段
A B 两表上都有
col1字段表示普通字段
select xxx from A
where A.idx1 between mmm and nnn
and exists (select 1 from B where B.idx2 =
@Repository、@Service、@Controller 和 @Component 将类标识为Bean
Spring 自 2.0 版本开始,陆续引入了一些注解用于简化 Spring 的开发。@Repository注解便属于最先引入的一批,它用于将数据访问层 (DAO 层 ) 的类标识为 Spring Bean。具体只需将该注解标注在 DAO类上即可。同时,为了让 Spring 能够扫描类
先看一下下面的错误代码,对写加了synchronized控制,保证了写的安全,但是问题在哪里呢?
public class testTh7 {
private String data;
public String read(){
System.out.println(Thread.currentThread().getName() + "read data "
网上已经有一大堆的设置步骤的了,根据我遇到的问题,整理一下,如下:
首先先去下载一个mongodb最新版,目前最新版应该是2.6
cd /usr/local/bin
wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.0.tgz
tar -zxvf mongodb-linux-x86_64-2.6.0.t
1.rust里绑定变量是let,默认绑定了的变量是不可更改的,所以如果想让变量可变就要加上mut。
let x = 1; let mut y = 2;
2.match 相当于erlang中的case,但是case的每一项后都是分号,但是rust的match却是逗号。
3.match 的每一项最后都要加逗号,但是最后一项不加也不会报错,所有结尾加逗号的用法都是类似。
4.每个语句结尾都要加分