如果这篇文章对您有些用处,请点赞告诉我O(∩_∩)O
设计模式的文章千千万,其实不用写的太复杂,JDK就是最好sample。他怎么用我们就怎么用。
以下定义均来自《GOF设计模式》
1、SINGLETON(单件)— 对象创建型模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式有很多形式,JDK中Runtime类使用饿汉,简单且安全。
具体步骤:
1、构造方法私有
2、成员变量实例化
3、提供获取实例的方法
public class Runtime {
private static Runtime currentRuntime = new Runtime(); //2、成员变量实例化
public static Runtime getRuntime() { //3、提供获取实例的方法
return currentRuntime;
}
private Runtime() {} //1、构造方法私有
....
}
测试:java执行mac上的pwd命令
Runtime runtime = Runtime.getRuntime();
try (InputStream in = runtime.exec("pwd").getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));) {
String line = "";
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
结果:/Users/yaoguangyao/DEV/EWS-JAVA/tij
2.、STRATEGY(策略)— 对象行为型模式
定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独 立于使用它的客户而变化。
JDK中Comparable 和 Comparetor使用两种形式的策略模式实现了比较以及排序。
(1)Comparable 目标对象实现算法接口,内置算法
具体步骤:
1、抽象出算法接口
2,使用算法接口
3、目标对象实现算法接口
public interface Comparable<T> { //1、抽象出算法接口
public int compareTo(T o); //比较算法
}
Collections.sort
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null); //T必须实现Comparable
}
Collections.sort内部使用TimSort.binarySort 二分排序,在插入排序基础上加入二分思想,每次和中间值比较使用的是compareTo方法。
private static void binarySort(Object[] a, int lo, int hi, int start) {
......
for ( ; start < hi; start++) {
Comparable pivot = (Comparable) a[start]; //当前值,将当前元素向上转型为Comparable
......
while (left < right) {
int mid = (left + right) >>> 1; //取中间索引
if (pivot.compareTo(a[mid]) < 0) //2、使用算法接口:使用Comparable.compareTo方法比较当前值和中间值
right = mid;
else
left = mid + 1;
}
......
}
测试:商品按照数量倒序且id正序排序
class Product implements Comparable<Product> {
private Long id;
private String name;
private Integer count;
......
@Override
public int compareTo(Product o) { //3、目标对象实现算法接口
if (o != null) {
if (this.count > o.count) {
return -1; // 按照数量倒序
} else if (this.count < o.count) {
return 1;
} else if (this.id > o.id) {
return 1; // 按照id正序
} else if (this.id < o.id) {
return -1;
} else {
return 0;
}
}
return 0;
}
@Override
public String toString() {
return "[id:" + id + ", name:" + name + ", count:" + count + "]";
}
public static void main(String[] args) {
List<Product> products = new ArrayList<>();
products.add(new Product(1l, "可乐", 50));
products.add(new Product(2l, "雪碧", 70));
products.add(new Product(3l, "酸奶", 70));
products.add(new Product(4l, "牛奶", 80));
Collections.sort(products);
System.out.println(products);
}
}
结果:
[[id:4, name:牛奶, count:80], [id:2, name:雪碧, count:70], [id:3, name:酸奶, count:70], [id:1, name:可乐, count:50]]
(2)Comparetor 目标对象无需实现算法接口,外置算法
具体步骤:
1、抽象出算法接口
2、使用外置算法
3、外置算法实现
public interface Comparator<T> { //1、抽象出算法接口
int compare(T o1, T o2);
.....
}
Collections.sort
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
Collections.sort(List) 和 Collections.sort(List, Comparator) 区别,在于后者目标对象没有实现算法接口,而是算法外置,同样使用二分排序,每次和中间值比较使用的是Comparator.compare方法。
private static <T> void binarySort(T[] a, int lo, int hi, int start,
Comparator<? super T> c) {
......
for ( ; start < hi; start++) {
T pivot = a[start];
......
while (left < right) {
int mid = (left + right) >>> 1; //取中间索引
if (c.compare(pivot, a[mid]) < 0) //2、使用外置算法:使用Comparator.compare方法比较当前值和中间值
right = mid;
else
left = mid + 1;
}
......
}
测试:商品按照数量倒序且id正序排序
class Prodcut {
......
public static void main(String[] args) {
List<Product> products = new ArrayList<>();
products.add(new Product(1l, "可乐", 50));
products.add(new Product(2l, "雪碧", 70));
products.add(new Product(3l, "酸奶", 70));
products.add(new Product(4l, "牛奶", 80));
Collections.sort(products, new Comparator<Product>() { //3、外置算法实现
@Override
public int compare(Product o1, Product o2) {
if(o1 != null && o2 != null) {
if (o1.count > o2.count) {
return -1; // 数量倒序
} else if (o1.count < o2.count) {
return 1;
} else if (o1.id > o2.id) {
return 1; // id正序
} else if (o1.id < o2.id) {
return -1;
} else {
return 0;
}
}
return 0;
}
});
System.out.println(products);
}
}
结果:
[[id:4, name:牛奶, count:80], [id:2, name:雪碧, count:70], [id:3, name:酸奶, count:70], [id:1, name:可乐, count:50]]
3、ADAPTER(适配器)— 类对象结构型模式
将一个类的接口转换成客户希望的另外一个接口。 而不能一起工作的那些类可以一起工作。
在没有字符流之前,字节流只能从文件里读出byte[]。
(不要使用DataInputStream.readUTF读取字符串,它只能按照阉割过的UTF-8解码)
如果要读出字符串需要:
文件 -> 字节流 -> byte[] -> 根据UTF-8等各种编码规则去解码 -> char[]
有了字符流之后,不需要自己解码。可以直接读出char[],那么JDK中将已有的字节流转换为字符流的InputStreamReader类就使用了适配器模式。
具体步骤:
1、抽象出需要适配的接口
2、构造方法传入被适配对象
3、使用成员变量保存被适配对象
4、使用被适配对象去实现适配接口
public class InputStreamReader extends Reader { //1、抽象出需要适配的接口:字符流Reader
private final StreamDecoder sd; //流解码器
public InputStreamReader(InputStream in) { //2、构造方法传入被适配对象:字节流InputStream
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // 3、使用成员变量保存被适配对象:这里保存的是根据in创建解码器sd
} catch (UnsupportedEncodingException e) {
// The default encoding should always be available
throw new Error(e);
}
}
......
public int read(char cbuf[], int offset, int length) throws IOException {
return sd.read(cbuf, offset, length); //4、使用被适配对象去实现适配接口:这里实际使用字节流创建的解码器,去读取字节并解码为字符
}
......
}
BufferedReader.readLine方法,实际是先通过fill()方法读入到成员变量char cb[]中,再一行一行读出。
public class BufferedReader extends Reader {
......
private void fill() throws IOException {
......
int n;
do {
n = in.read(cb, dst, cb.length - dst); //实际使用InputStreamReader.read方法读取字符
} while (n == 0);
......
}
}
测试代码同"SINGLETON(单件)— 对象创建型模式"