分类
常用设计模式共有24种,分为三大类:创建型模式、行为型模式、结构型模式。
创建型模式提供了一种在创建对象的同时,隐藏创建逻辑的方式,而不是使用新的运算符直接实例化对象。常用的创建型模式包括:
- 单例模式
- 简单工厂模式
- 工厂模式
- 抽象工厂模式
- 生成器模式
- 原型模式
行为型模式特别关注对象之间的通信。常用的包括:
- 责任链模式
- 命令模式
- 迭代器模式
- 访问者模式
- 中介者模式
- 备忘录模式
- 观察者模式
- 状态模式
- 策略模式
- 模板方式模式
- 解释器模式
结构型模式关注类和对象的组合,继承的概念被用来组合接口和定义组合对象获得新功能的方式。常用的包括:
- 享元模式
- 适配器模式
- 组合模式
- 代理模式
- 桥接模式
- 装饰器模式
- 外观模式
接口和抽象类
类比现实,人做事总是先思考再去实现。java语言反映思考—实现这一过程时,通过接口(Interface)和抽象类(Abstract)来反映思考阶段;通过类(Class)来反映实现阶段。
接口与抽象类有何区别?这里可以把遇见的常见问题分为两类,一类是“顺序”问题,另一类是“顺序+共享”。
例如,描绘一个生产汽车的接口,生产汽车可由钢板切割、压膜、组装和喷漆构成,这些工序是顺序关系。
例如,描绘组装多种价位的计算机,参数配置如下图所示。
可以看出,配置n类计算机时,硬盘、光驱、显示器都是不同类型的,是并列结构(也可以看作是顺序结构)。而主板是相同类型,属于共享结构,转化成抽象类如下:
反射
Java反射(Java Reflection)是指在程序运行时获取已知名称的类或已有对象相关信息的一种机制,包括类的方法、属性、父类等信息,还包括实例的创建和实例类型的判断等。
显式调用
public class A{
void func(){}
public static void main(String[] args){
A obj = new A();
obj.func();
}
}
隐式调用
在JDK中,主要由以下类来实现Java反射机制,位于java.lang.reflect包中。
- Class类:代表一个类
- Constructor类:代表类的构造方法
- Filed类:代表类的成员变量(成员变量也成为类的属性)
- Method类:代表类的方法
使用上述Class、Constructor、Filed、Method四个类,能解析无穷多的系统类和自定义类结构,创建对象及方法执行等功能,且形式是一致的。
例1:统一形式解析类的构造方法、成员变量、成员方法。
public class A {
int m;
public A() {
}
public A(int m) {
this.m = m;
}
private void func1() {
}
private void func2() {
}
public static void main(String[] args) throws Exception {
// 加载并初始化指定的类A
Class classInfo = Class.forName("chapter1.demo1.A");
// 获得类的构造
System.out.println("类A构造函数如下所示:");
Constructor cons[] = classInfo.getConstructors();
for (int i = 0; i < cons.length; i++) {
System.out.println(cons[i].toString());
}
// 获得类的所有变量
System.out.println();
System.out.println("类A的所有变量如下所示:");
Field fields[] = classInfo.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i].toString());
}
// 获得所有的方法
System.out.println();
System.out.println("类A的方法如下所示:");
Method methods[] = classInfo.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println(methods[i].toString());
}
}
}
例2:统一形式调用构造方法实例。
public class A {
public A(){
System.out.println("This is A:");
}
public A(Integer m){
System.out.println("This is A:"+m);
}
public A(String s , Integer m){
System.out.println(s+":"+m);
}
public static void main(String[] args) throws Exception{
Class classInfo = Class.forName("chapter1.demo2.A");
// 第1种方法
Constructor cons[] = classInfo.getConstructors();
for (Constructor c : cons){
System.out.println(c.toString());
}
// 调用无参构造函数
cons[0].newInstance();
// 调用1个参数构造函数
cons[1].newInstance(new Object[]{10});
// 调用2个参数构造函数
cons[2].newInstance(new Object[]{"Hellow",2010});
// 第2种方法
System.out.println("\n\n\n");
// 调用无参构造函数
Constructor c = classInfo.getConstructor();
c.newInstance();
// 调用1个参数构造方法
c = classInfo.getConstructor(new Class[]{Integer.class});
c.newInstance(new Object[]{10});
// 调用2个参数构造函数
c = classInfo.getConstructor(new Class[]{String.class,Integer.class});
c.newInstance(new Object[]{"Hellow",2010});
}
}
例3:统一形式调用成员方法。
public class A {
public void func1() {
System.out.println("This is func1:");
}
public void func2(Integer m) {
System.out.println("This is func2:" + m);
}
public void func3(String s, Integer m) {
System.out.println("This is func3:" + s + " " + m);
}
public static void main(String[] args) throws Exception {
Class classInfo = Class.forName("chapter1.demo3.A");
// 调用无参构造函数,生成新的实例对象
Object obj = classInfo.getConstructor().newInstance();
// 调用无参成员函数func1
Method m1 = classInfo.getMethod("func1");
m1.invoke(obj);
// 调用1个参数成员函数func2
Method m2 = classInfo.getMethod("func2", Integer.class);
m2.invoke(obj, new Object[]{10});
// 调用2个参数成员函数func3
Method m3 = classInfo.getMethod("func3", String.class, Integer.class);
m3.invoke(obj, new Object[]{"Hello", 2010});
}
}
例4:通用的调用方法,提供类名字字符串、方法名字符串、方法参数值,运行反射机制就能执行该方法。
boolean process(String className, String funcName, Object[] para) throws Exception {
// 获取类信息对象
Class classInfo = Class.forName(className);
// 形成函数参数序列
Class c[] = new Class[para.length];
for (int i = 0; i < c.length; i++) {
c[i] = para[i].getClass();
}
// 调用无参构造函数
Constructor ct = classInfo.getConstructor();
Object obj = ct.newInstance();
// 获得函数方法信息
Method mt = classInfo.getMethod(funcName,c);
// 执行该方法
mt.invoke(obj,para);
return true;
}
运用反射技术编程,可以大大提高应用框架的稳定程度。具体表现在当新加功能的时候,仅需增加相应的工具类,而框架调用可能不需要发生变化。如下例:
例5
public interface IMsg {
void process(String msg);
}
public class ConsoleMsg implements IMsg{
@Override
public void process(String msg) {
System.out.println(msg);
}
}
public class FileMsg implements IMsg {
@Override
public void process(String msg) {
System.out.println("Save msg to File");
}
}
public class Test1 {
public static void main(String[] args) throws Exception {
IMsg obj = null;
obj = (IMsg) Class.forName("chapter1.demo4.ConsoleMsg").newInstance();
obj.process("hello world!");
}
}
反射与Properties文件
Properties类表示了一个持久的属性集,属性列表中每个键及其键值都是一个字符串。常用函数如下:
- Properties():创建一个无默认值的空属性列表
- void load(InputString inStream ):从输入流中读取属性列表
- String getProperties(String key):获取指定键key的键值,以字符串的形式返回
- void setProperties(String key, String value):设置对象中key的键值
例6:修改例5
msg.properties文件
func = chapter1.demo4.ConsoleMsg
public class Test2 {
public static void main(String[] args) throws Exception{
Properties p = new Properties();
p.load(new FileInputStream("E:\\IdeaProjects\\DesignPattern\\src\\chapter1\\demo4\\msg.properties"));
String cname = p.getProperty("func");
IMsg obj = null;
obj = (IMsg) Class.forName(cname).newInstance();
obj.process("hello world!");
}
}
例6:XML形式
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>求圆和三角形面积</comment>
<entry key="func">chapter1.demo4.ConsoleMsg</entry>
</properties>
public class Test3 {
public static void main(String[] args) throws Exception {
Properties p = new Properties();
// 用loadFromXML()代替了load()方法
p.loadFromXML(new FileInputStream("E:\\WorkStations\\IdeaProjects\\DesignPattern\\src\\chapter1\\demo4\\msg2.xml"));
String cname = p.getProperty("func");
IMsg obj = null;
obj = (IMsg) Class.forName(cname).newInstance();
obj.process("hello world!");
}
}