需求
开发一个打印机程序,可灵活配置使用彩色墨盒或灰色墨盒,可灵活配置打印页面的纸张大小。
开发步骤
(1)定义墨盒和纸张的接口标准。
(2)使用接口标准开发打印机。
(3)组装打印机。
(4)运行打印机。
(1)定义组件接口
墨盒接口代码:
/**
* 墨盒接口。
*/
public interface Ink {
/**
* 定义打印采用的颜色的方法。
*
* @param r 红色值
* @param g 绿色值
* @param b 蓝色值
* @return 返回打印采用的颜色
*/
public String getColor(int r, int g, int b);
}
纸张接口代码:
/**
* 纸张接口。
*/
public interface Paper {
public static final String newline = "\r\n";
/**
* 输出一个字符到纸张。
*/
public void putInChar(char c);
/**
* 得到输出到纸张上的内容。
*/
public String getContent();
}
(2)使用接口开发打印机(面向接口编程)
墨盒接口的实现类——彩色墨盒,代码:
package cn.ink;
import java.awt.Color;
import cn.printer.Ink;
/**
* 彩色墨盒。ColorInk实现Ink接口。
*/
public class ColorInk implements Ink {
// 打印采用彩色
public String getColor(int r, int g, int b) {
Color color = new Color(r, g, b);
return "#" + Integer.toHexString(color.getRGB()).substring(2);
}
}
墨盒接口的实现类——灰色墨盒,代码:
import java.awt.Color;
import cn.printer.Ink;
/**
* 灰色墨盒。GreyInk实现Ink接口。
*/
public class GreyInk implements Ink {
// 打印采用灰色
public String getColor(int r, int g, int b) {
int c = (r + g + b) / 3;
Color color = new Color(c, c, c);
return "#" + Integer.toHexString(color.getRGB()).substring(2);
}
}
纸张接口的实现类——文本纸张,代码:
package cn.paper;
import cn.printer.Paper;
/**
* 文本打印纸张实现。TextPaper实现Paper接口。
*/
public class TextPaper implements Paper {
// 每行字符数
private int charPerLine = 16;
// 每页行数
private int linePerPage = 5;
// 纸张中内容
private String content = "";
// 当前横向位置,从0到charPerLine-1
private int posX = 0;
// 当前行数,从0到linePerPage-1
private int posY = 0;
// 当前页数
private int posP = 1;
public String getContent() {
String ret = this.content;
// 补齐本页空行,并显示页码
if (!(posX == 0 && posY == 0)) {
int count = linePerPage - posY;
for (int i = 0; i < count; ++i) {
ret += Paper.newline;
}
ret += "== 第" + posP + "页 ==";
}
return ret;
}
public void putInChar(char c) {
content += c;
++posX;
// 判断是否换行
if (posX == charPerLine) {
content += Paper.newline;
posX = 0;
++posY;
}
// 判断是否翻页
if (posY == linePerPage) {
content += "== 第" + posP + "页 ==";
content += Paper.newline + Paper.newline;
posY = 0;
++posP;
}
}
// setter方法,用于属性注入
public void setCharPerLine(int charPerLine) {
this.charPerLine = charPerLine;
}
// setter方法,用于属性注入
public void setLinePerPage(int linePerPage) {
this.linePerPage = linePerPage;
}
}
(3)组装打印机
打印机程序类,代码:
package cn.printer;
/**
* 打印机程序。
*/
public class Printer {
// 面向接口编程,而不是具体的实现类
private Ink ink = null;
// 面向接口编程,而不是具体的实现类
private Paper paper = null;
/**
* 设值注入所需的setter方法。
* @param ink 传入墨盒参数
*/
public void setInk(Ink ink) {
this.ink = ink;
}
/**
* 设值注入所需的setter方法。
* @param paper 传入纸张参数
*/
public void setPaper(Paper paper) {
this.paper = paper;
}
/**
* 打印机打印方法。
* @param str 传入打印内容
*/
public void print(String str) {
// 输出颜色标记
System.out.println("使用" + ink.getColor(255, 200, 0) + "颜色打印:\n");
// 逐字符输出到纸张
for (int i = 0; i < str.length(); ++i) {
paper.putInChar(str.charAt(i));
}
// 将纸张的内容输出
System.out.print(paper.getContent());
}
}
(4)注入组装打印机时所依赖的对象
相当于把创建和组装的需求通过配置文件告诉Spring,由Spring负责实施,而不是通过硬编码实现(需要提前为Printer类的ink和paper属性增加setter方法,Spring是通过调用setter方法实现的注入)。
编辑applicationContext.xml文件,使用Spring创建Ink、Paper和Printer的实例并进行组装。
Spring配置文件applicationContext.xml代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<!-- 定义彩色墨盒bean,该bean的id是colorInk,class指定该bean实例的实现类 -->
<bean id="colorInk" class="cn.ink.ColorInk" />
<!-- 定义灰色墨盒bean,该bean的id是greyInk,class指定该bean实例的实现类 -->
<bean id="greyInk" class="cn.ink.GreyInk" />
<!-- 定义A4纸张bean,该bean的id是a4Paper,class指定该bean实例的实现类 -->
<bean id="a4Paper" class="cn.paper.TextPaper">
<!-- property元素用来指定需要容器注入的属性,charPerLine需要容器注入, TextPaper类必须拥有setCharPerLine()方法。-->
<!-- 注入每行字符数 -->
<property name="charPerLine" value="10" />
<!-- property元素用来指定需要容器注入的属性,linePerPage需要容器注入,TextPaper类必须拥有setLinePerPage()方法。 -->
<!-- 注入每页行数 -->
<property name="linePerPage" value="8" />
</bean>
<!-- 定义B5纸张bean,该bean的id是b5Paper,class指定该bean实例的实现类 -->
<bean id="b5Paper" class="cn.paper.TextPaper">
<!-- property元素用来指定需要容器注入的属性,charPerLine需要容器注入, TextPaper类必须拥有setCharPerLine()方法。注入每行字符数 -->
<property name="charPerLine" value="6" />
<!-- property元素用来指定需要容器注入的属性,linePerPage需要容器注入, TextPaper类必须拥有setLinePerPage()方法。注入每页行数 -->
<property name="linePerPage" value="5" />
</bean>
<!-- 组装打印机。定义打印机bean,该bean的id是printer, class指定该bean实例的实现类 -->
<bean id="printer" class="cn.printer.Printer">
<!-- 通过ref属性注入已经定义好的bean -->
<!-- 注入彩色墨盒 -->
<property name="ink" ref="colorInk"></property>
<!-- 注入B5打印纸张 -->
<property name="paper" ref="b5Paper"></property>
</bean>
</beans>
(5)运行打印机
运行打印机的测试类代码:
package cn.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.printer.Printer;
/**
* 测试运行打印机。
*/
public class PrinterTest {
@Test
public void printerTest() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
// 通过Printer bean的id来获取Printer实例
Printer printer = (Printer) context.getBean("printer");
String content = "几位轻量级容器的作者曾骄傲地对我说:这些容器非常有"
+ "用,因为它们实现了“控制反转”。这样的说辞让我深感迷惑:控"
+ "制反转是框架所共有的特征,如果仅仅因为使用了控制反转就认为"
+ "这些轻量级容器与众不同,就好像在说“我的轿车是与众不同的," + "因为它有4个轮子。”";
printer.print(content);
}
}