设计模式

设计模式

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. 饿汉式

实现步骤如下:

  1. 构造器私有化 ===> 防止直接 new
  2. 类的内部创建对象(该对象式 static)
  3. 向外暴露一个静态的公共方法: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 对象,从而保证了单例
注意:懒汉式有线程安全问题:

  1. 破坏了单例
  2. 3个线程创建了3个对象
  3. 只是最后保存了最后1个线程创建的对象
posted @ 2023-03-06 14:44  爱新觉罗LQ  阅读(6)  评论(0编辑  收藏  举报