设计模式
设计模式
1. 修饰器模式
2. 模板设计模式
在 BufferedReader_ 中对方法进行了封装
package IO_;
/**
* 做成处理流 / 包装流
*/
public class BufferedReader_ extends Reader58 {
private Reader58 reader58; // 属性是 Reader58 类型
// 接收 Reader58 子类对象
public BufferedReader_(Reader58 reader58) {
this.reader58 = reader58;
}
// 我们这个继承 Reader58的,那么我们就可以调用 Reader58的方法
// 1)可以原封不动地调用方法
public void readFile() { // 封装一层
reader58.readFile();
}
public void readString(){
reader58.readString();
}
// 让方法更加灵活,多次读取文件,或者加缓冲 char[] ...
public void readFiles(int num) {
for (int i = 0; i < num; i++) {
reader58.readFile();
}
}
// 扩展 readString,批量处理字符串数据
public void readString(int num) {
for (int i = 0; i < num; i++) {
reader58.readString();
}
}
}
package IO_;
public class Test_ {
public static void main(String[] args) {
BufferedReader_ bufferedReader_ = new BufferedReader_(new Filereader_());
bufferedReader_.readFiles(3);
BufferedReader_ bufferedReader_1 = new BufferedReader_(new StringReader_());
bufferedReader_1.readString(4);
}
}
3. 代理模式(Proxy)
- java是 单继承 的,在某些情况下,一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然已经不可能了
- java设计者们提供了另外一个方式创建线程,就是通过实现 Runnable 接口来创建线程
核心点:只有 Thread 类的 start0() 方法才可以开启线程【start ---> start0 ---> run(动态绑定)】
我自己没有 start 方法,我让你代替我完成【静态代理模式】
// 线程代理类,模拟了一个极简的 Thread 类
class ThreadProxy implements Runnable{ // 你可以把 Proxy类当做 ThreadProxy (买票代理。跑腿的)
private Runnable target = null; // 属性,类型是 Runnable
@Override
public void run() {
if (target != null) {
target.run(); // 动态绑定
}
}
public ThreadProxy(Runnable target) {
this.target = target;
}
public void start(){
start0(); // 这个方法是真正实现多线程的方法
}
public void start0(){
run();
}
}
4. 单例模式【8种方式】
创建时机 | 存在问题 | |
---|---|---|
饿汉式 | 类加载 | 有浪费资源的可能 |
懒汉式 | 使用时才创建 | 线程安全问题 |
- 采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例
- 并且该类只提供一个取得其对象实例的方法
饿汉 | 懒汉 | |
---|---|---|
单例 | lazy-init="false"【默认】 | lazy-init="true" |
多例 XML:scope="prototype" 注解下配置:@Scope("prototype") |
无 |
经典单例:
public class Runtime {
private static final Runtime currentRuntime = new Runtime(); // 饿汉式单例
private static Version version;
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
public void exit(int status) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkExit(status);
}
Shutdown.exit(status);
}
public void addShutdownHook(Thread hook) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("shutdownHooks"));
}
ApplicationShutdownHooks.add(hook);
}
public boolean removeShutdownHook(Thread hook) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("shutdownHooks"));
}
return ApplicationShutdownHooks.remove(hook);
}
public void halt(int status) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkExit(status);
}
Shutdown.beforeHalt();
Shutdown.halt(status);
}
public Process exec(String command) throws IOException {
return exec(command, null, null);
}
public Process exec(String command, String[] envp) throws IOException {
return exec(command, envp, null);
}
public Process exec(String command, String[] envp, File dir)
throws IOException {
if (command.isEmpty())
throw new IllegalArgumentException("Empty command");
StringTokenizer st = new StringTokenizer(command);
String[] cmdarray = new String[st.countTokens()];
for (int i = 0; st.hasMoreTokens(); i++)
cmdarray[i] = st.nextToken();
return exec(cmdarray, envp, dir);
}
public Process exec(String cmdarray[]) throws IOException {
return exec(cmdarray, null, null);
}
public Process exec(String[] cmdarray, String[] envp) throws IOException {
return exec(cmdarray, envp, null);
}
public Process exec(String[] cmdarray, String[] envp, File dir)
throws IOException {
return new ProcessBuilder(cmdarray)
.environment(envp)
.directory(dir)
.start();
}
public native int availableProcessors();
public native long freeMemory();
public native long totalMemory();
public native long maxMemory();
public native void gc();
public void runFinalization() {
SharedSecrets.getJavaLangRefAccess().runFinalization();
}
@CallerSensitive
public void load(String filename) {
load0(Reflection.getCallerClass(), filename);
}
void load0(Class<?> fromClass, String filename) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkLink(filename);
}
if (!(new File(filename).isAbsolute())) {
throw new UnsatisfiedLinkError(
"Expecting an absolute path of the library: " + filename);
}
ClassLoader.loadLibrary(fromClass, filename, true);
}
@CallerSensitive
public void loadLibrary(String libname) {
loadLibrary0(Reflection.getCallerClass(), libname);
}
void loadLibrary0(Class<?> fromClass, String libname) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkLink(libname);
}
if (libname.indexOf((int)File.separatorChar) != -1) {
throw new UnsatisfiedLinkError(
"Directory separator should not appear in library name: " + libname);
}
ClassLoader.loadLibrary(fromClass, libname, false);
}
public static Version version() {
if (version == null) {
version = new Version(VersionProps.versionNumbers(),
VersionProps.pre(), VersionProps.build(),
VersionProps.optional());
}
return version;
}
public static final class Version
implements Comparable<Version>
{
private final List<Integer> version;
private final Optional<String> pre;
private final Optional<Integer> build;
private final Optional<String> optional;
private Version(List<Integer> unmodifiableListOfVersions,
Optional<String> pre,
Optional<Integer> build,
Optional<String> optional)
{
this.version = unmodifiableListOfVersions;
this.pre = pre;
this.build = build;
this.optional = optional;
}
public static Version parse(String s) {
if (s == null)
throw new NullPointerException();
// Shortcut to avoid initializing VersionPattern when creating
// feature-version constants during startup
if (isSimpleNumber(s)) {
return new Version(List.of(Integer.parseInt(s)),
Optional.empty(), Optional.empty(), Optional.empty());
}
Matcher m = VersionPattern.VSTR_PATTERN.matcher(s);
if (!m.matches())
throw new IllegalArgumentException("Invalid version string: '"
+ s + "'");
// $VNUM is a dot-separated list of integers of arbitrary length
String[] split = m.group(VersionPattern.VNUM_GROUP).split("\\.");
Integer[] version = new Integer[split.length];
for (int i = 0; i < split.length; i++) {
version[i] = Integer.parseInt(split[i]);
}
Optional<String> pre = Optional.ofNullable(
m.group(VersionPattern.PRE_GROUP));
String b = m.group(VersionPattern.BUILD_GROUP);
// $BUILD is an integer
Optional<Integer> build = (b == null)
? Optional.empty()
: Optional.of(Integer.parseInt(b));
Optional<String> optional = Optional.ofNullable(
m.group(VersionPattern.OPT_GROUP));
// empty '+'
if (!build.isPresent()) {
if (m.group(VersionPattern.PLUS_GROUP) != null) {
if (optional.isPresent()) {
if (pre.isPresent())
throw new IllegalArgumentException("'+' found with"
+ " pre-release and optional components:'" + s
+ "'");
} else {
throw new IllegalArgumentException("'+' found with neither"
+ " build or optional components: '" + s + "'");
}
} else {
if (optional.isPresent() && !pre.isPresent()) {
throw new IllegalArgumentException("optional component"
+ " must be preceeded by a pre-release component"
+ " or '+': '" + s + "'");
}
}
}
return new Version(List.of(version), pre, build, optional);
}
private static boolean isSimpleNumber(String s) {
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
char lowerBound = (i > 0) ? '0' : '1';
if (c < lowerBound || c > '9') {
return false;
}
}
return true;
}
public int feature() {
return version.get(0);
}
public int interim() {
return (version.size() > 1 ? version.get(1) : 0);
}
public int update() {
return (version.size() > 2 ? version.get(2) : 0);
}
public int patch() {
return (version.size() > 3 ? version.get(3) : 0);
}
@Deprecated(since = "10")
public int major() {
return feature();
}
@Deprecated(since = "10")
public int minor() {
return interim();
}
@Deprecated(since = "10")
public int security() {
return update();
}
public List<Integer> version() {
return version;
}
public Optional<String> pre() {
return pre;
}
public Optional<Integer> build() {
return build;
}
public Optional<String> optional() {
return optional;
}
@Override
public int compareTo(Version obj) {
return compare(obj, false);
}
public int compareToIgnoreOptional(Version obj) {
return compare(obj, true);
}
private int compare(Version obj, boolean ignoreOpt) {
if (obj == null)
throw new NullPointerException();
int ret = compareVersion(obj);
if (ret != 0)
return ret;
ret = comparePre(obj);
if (ret != 0)
return ret;
ret = compareBuild(obj);
if (ret != 0)
return ret;
if (!ignoreOpt)
return compareOptional(obj);
return 0;
}
private int compareVersion(Version obj) {
int size = version.size();
int oSize = obj.version().size();
int min = Math.min(size, oSize);
for (int i = 0; i < min; i++) {
int val = version.get(i);
int oVal = obj.version().get(i);
if (val != oVal)
return val - oVal;
}
return size - oSize;
}
private int comparePre(Version obj) {
Optional<String> oPre = obj.pre();
if (!pre.isPresent()) {
if (oPre.isPresent())
return 1;
} else {
if (!oPre.isPresent())
return -1;
String val = pre.get();
String oVal = oPre.get();
if (val.matches("\\d+")) {
return (oVal.matches("\\d+")
? (new BigInteger(val)).compareTo(new BigInteger(oVal))
: -1);
} else {
return (oVal.matches("\\d+")
? 1
: val.compareTo(oVal));
}
}
return 0;
}
private int compareBuild(Version obj) {
Optional<Integer> oBuild = obj.build();
if (oBuild.isPresent()) {
return (build.isPresent()
? build.get().compareTo(oBuild.get())
: -1);
} else if (build.isPresent()) {
return 1;
}
return 0;
}
private int compareOptional(Version obj) {
Optional<String> oOpt = obj.optional();
if (!optional.isPresent()) {
if (oOpt.isPresent())
return -1;
} else {
if (!oOpt.isPresent())
return 1;
return optional.get().compareTo(oOpt.get());
}
return 0;
}
@Override
public String toString() {
StringBuilder sb
= new StringBuilder(version.stream()
.map(Object::toString)
.collect(Collectors.joining(".")));
pre.ifPresent(v -> sb.append("-").append(v));
if (build.isPresent()) {
sb.append("+").append(build.get());
if (optional.isPresent())
sb.append("-").append(optional.get());
} else {
if (optional.isPresent()) {
sb.append(pre.isPresent() ? "-" : "+-");
sb.append(optional.get());
}
}
return sb.toString();
}
@Override
public boolean equals(Object obj) {
boolean ret = equalsIgnoreOptional(obj);
if (!ret)
return false;
Version that = (Version)obj;
return (this.optional().equals(that.optional()));
}
public boolean equalsIgnoreOptional(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof Version))
return false;
Version that = (Version)obj;
return (this.version().equals(that.version())
&& this.pre().equals(that.pre())
&& this.build().equals(that.build()));
}
/**
* Returns the hash code of this version.
*
* @return The hashcode of this version
*/
@Override
public int hashCode() {
int h = 1;
int p = 17;
h = p * h + version.hashCode();
h = p * h + pre.hashCode();
h = p * h + build.hashCode();
h = p * h + optional.hashCode();
return h;
}
}
private static class VersionPattern {
// $VNUM(-$PRE)?(\+($BUILD)?(\-$OPT)?)?
// RE limits the format of version strings
// ([1-9][0-9]*(?:(?:\.0)*\.[1-9][0-9]*)*)(?:-([a-zA-Z0-9]+))?(?:(\+)(0|[1-9][0-9]*)?)?(?:-([-a-zA-Z0-9.]+))?
private static final String VNUM
= "(?<VNUM>[1-9][0-9]*(?:(?:\\.0)*\\.[1-9][0-9]*)*)";
private static final String PRE = "(?:-(?<PRE>[a-zA-Z0-9]+))?";
private static final String BUILD
= "(?:(?<PLUS>\\+)(?<BUILD>0|[1-9][0-9]*)?)?";
private static final String OPT = "(?:-(?<OPT>[-a-zA-Z0-9.]+))?";
private static final String VSTR_FORMAT = VNUM + PRE + BUILD + OPT;
static final Pattern VSTR_PATTERN = Pattern.compile(VSTR_FORMAT);
static final String VNUM_GROUP = "VNUM";
static final String PRE_GROUP = "PRE";
static final String PLUS_GROUP = "PLUS";
static final String BUILD_GROUP = "BUILD";
static final String OPT_GROUP = "OPT";
}
}
4.1. 饿汉式
实现步骤如下:
- 构造器私有化 ===> 防止直接 new
- 类的内部创建对象(该对象式 static)
- 向外暴露一个静态的公共方法:getInstance
只要类一加载,这个对象就会实例化,并且只会实例化一次
即使你没有使用到这个 gf,它也会被实例化
package single;
public class SingleTon {
public static void main(String[] args) {
System.out.println(GirlFriend.a);
}
}
class GirlFriend{
private String name;
public static int a = 1;
private static GirlFriend gf = new GirlFriend("BJQ");
private GirlFriend(String name) {
System.out.println("构造器被调用");
this.name = name;
}
public static GirlFriend getInstance(){
return gf;
}
@Override
public String toString() {
return "GirlFriend{" +
"name='" + name + '\'' +
'}';
}
}
4.2. 懒汉式
对象,通常是重量级的对象,饿汉式可能造成创建了对象,但是没有使用
package single;
public class SingleTon {
public static void main(String[] args) {
System.out.println(Cat.a);
}
}
class Cat{
private String name;
public static int a = 1;
private static Cat cat;
private Cat(String name) {
this.name = name;
}
public static Cat getInstance(){
if (cat == null){
cat = new Cat("小白");
}
return cat;
}
}
发现此时,并没有调用构造器
只有调用 getInstance() 方法时,才会调用到构造器,而且仅一次
package single;
public class SingleTon {
public static void main(String[] args) {
System.out.println(Cat.a);
Cat instance = Cat.getInstance();
Cat instance1 = Cat.getInstance();
Cat instance2 = Cat.getInstance();
System.out.println(instance == instance1);
System.out.println(instance1 == instance2);
}
}
class Cat{
private String name;
public static int a = 1;
private static Cat cat;
private Cat(String name) {
this.name = name;
}
public static Cat getInstance(){
if (cat == null){
cat = new Cat("小白");
}
return cat;
}
}
懒汉式,只有当用户使用 getInstance时,才会返回 cat 对象,后面再次调用时,会返回上次创建的 cat 对象,从而保证了单例
注意:懒汉式有线程安全问题:
- 破坏了单例
- 3个线程创建了3个对象
- 只是最后保存了最后1个线程创建的对象