java设计模式浅谈(单例模式,模板模式,工厂模式,代理模式)

这篇文章讲述的是java设计模式,包括单例模式、工厂模式、代理模式,如有错误或不当之处,希望各位大神批评指正。

什么是设计模式?

  • 设计模式:是指在大量的理论和实践中总结和理论化之后,优选的代码结构、编程风格、以及解决问题的思考模式。正如数学中的公式的使用一样。

  • 包括:

    1. 单例模式
    2. 模板模式
    3. 工厂模式
    4. 代理模式
    5. 等等…

单例模式

什么是单例模式?

单例模式是指,采用某种手段或者方法,保证整个软件系统中只能存在一个对象的实例,并且该实例只提供创建该对象的方法。

使用情况及优缺点

  • 使用情况:当您想控制实例数目,节省系统资源的时候,和一个全局使用的类频繁地创建与销毁的时候
  • 优点:节省系统资源的开销,避免内存的重复使用
  • 缺点:没有接口,不能继承

单例模式的例子

饿汉式

package com.cn.cmc.javadesignstyle;

public class SingletonDemo {
    //获取一个单例的实例
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance() ;
        Singleton singleton2 = Singleton.getInstance() ;
        System.out.println(singleton1 == singleton2);

        singleton1.claim();
    }
}
/**
 * 单例模式:程序运行中只能存在一个对象的实例
 * 
 * 设计步骤:1. 将构造器私有化,保证外部不能创建
 *          2. 初始化实例
 *          3. 私有化实例,向外界提供一个返回实例的接口
 *          4. 次公共方法必须通过类来调用static
 */
class Singleton{

    //将构造器私有化
    private Singleton(){

    }
    //在内部初始化一个实例
    //恶汉模式:在初始化类的时候直接实例化对象
    private static Singleton singleton = new Singleton() ;
    //懒汉模式:初始化时候不新建对象,在具体用到的时候在实例化
    private static Singleton singleton2 = null ;
    //向外部提供一个返回实例方法
    //饿汉
    public static Singleton getInstance() {
        return singleton;
    }
}

懒汉式

package com.cn.cmc.javadesignstyle;

public class SingletonDemo {
    //获取一个单例的实例
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance() ;
        Singleton singleton2 = Singleton.getInstance() ;
        System.out.println(singleton1 == singleton2);

        singleton1.claim();
    }
}
/**
 * 单例模式:程序运行中只能存在一个对象的实例
 * 
 * 设计步骤:1. 将构造器私有化,保证外部不能创建
 *          2. 初始化实例
 *          3. 私有化实例,向外界提供一个返回实例的接口
 *          4. 次公共方法必须通过类来调用static
 */
class Singleton{

    //将构造器私有化
    private Singleton(){

    }
    //在内部初始化一个实例
    //懒汉模式:初始化时候不新建对象,在具体用到的时候在实例化
    private static Singleton singleton2 = null ;
    //向外部提供一个返回实例方法
    public synchronized static Singleton getInstance2(){
        if(singleton2 == null){
            singleton2 = new Singleton() ;
        }
        return singleton2 ;
    }
}

注:使用懒汉模式时要注意线程安全问题,需要使用synchronized来控制进入创建实例方法的线程

静态内部类式

package com.cn.cmc.javadesignstyle;

public class SingletonDemo {
    //获取一个单例的实例
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance() ;
        Singleton singleton2 = Singleton.getInstance() ;
        System.out.println(singleton1 == singleton2);

    }
}
/**
 * 单例模式:程序运行中只能存在一个对象的实例
 * 
 * 设计步骤:1. 将构造器私有化,保证外部不能创建
 *          2. 初始化实例
 *          3. 私有化实例,向外界提供一个返回实例的接口
 *          4. 次公共方法必须通过类来调用static
 */
class Singleton{

    //将构造器私有化
    private Singleton(){

    }
    //静态内部类方式,在第一次使用时才会加载
    private static class SingletonClassInstance{
        private static final Singleton instance = new Singleton() ;
    }
    public static Singleton getInstance(){
        return SingletonClassInstance.instance ;
    }
}

枚举式

package com.cn.cmc.javadesignstyle;

public class SingletonDemo {
    //获取一个单例的实例
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.INSTANCE ;
        Singleton singleton2 = Singleton.INSTANCE ;
        System.out.println(singleton1 == singleton2);

    }
}
/**
 * 单例模式:程序运行中只能存在一个对象的实例
 * 
 * 设计步骤:1. 将构造器私有化,保证外部不能创建
 *          2. 初始化实例
 *          3. 私有化实例,向外界提供一个返回实例的接口
 *          4. 次公共方法必须通过类来调用static
 */
enum Singleton{

    //枚举类本身就是单例
    INSTANCE ;

    //相关操作
    public void operator(){
        System.out.println("操作...");
    }
}

单例模式总结

  • 饿汉式自身线程安全,调用高效但不支持延迟加载
  • 懒汉式需要synchronized保证线程安全,支持懒加载但调用低效
  • 静态内部类方式自身线程安全,支持懒加载且效率高效
  • 枚举式自身线程安全,编写方便效率高效但不支持懒加载

  • 选用时:若占用资源少,不需要懒加载,枚举式好于饿汉式
    若占用资源多,需要懒加载时,静态内部类式要好于懒汉式

模板模式

什么是模板模式

在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。

使用情况及优缺点

  • 使用情况:一些方法通用,却在每一个子类都重新写了这一方法。
  • 优点: 封装不变部分,扩展可变部分。 提取公共代码,便于维护。 行为由父类控制,子类实现。
  • 缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

模板模式的例子

package com.cn.cmc.javadesignstyle;

/**
 * 模板模式:父类只规定有什么通用方法,具体的实现交给子类来执行
 * 
 * 设计步骤:1. 将父类定义为抽象类
 *          2. 将父类的方法定义为抽象方法
 *          3.子类在继承父类时实现具体的方法
 */

//将父类定义为抽象类
abstract class Template{
    //将父类中的方法定义为抽象方法
    abstract void begin() ;
    abstract void say() ;
    abstract void end() ;
}

//子类在继承模板类时实现具体的方法
class Cat extends Template{
    void begin() {
        System.out.println("我是一只猫");
    }
    void say() {
        System.out.println("喵喵喵~");
    }
    void end() {
        System.out.println("说完了");
    }   
}
class Dog extends Template{
    void begin() {
        System.out.println("我是一只狗");
    }
    void say() {
        System.out.println("汪汪汪!");
    }
    void end() {
        System.out.println("说完了");
    }   
}

public class TemplatePattern {
    public static void main(String[] args) {
        //创建实现模板方法的类
        Cat cat = new Cat() ;
        Dog dog = new Dog() ;

        cat.begin();
        cat.say();
        cat.end();
        dog.begin();
        dog.say();
        dog.end();
    }
}

工厂模式

什么是工厂模式?

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

使用情况及优缺点

  • 使用情况:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
  • 优点:一个调用者想创建一个对象,只要知道其名称就可以了。 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 屏蔽产品的具体实现,调用者只关心产品的接口。
  • 缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

工厂模式的例子

简单工厂模式

package com.cn.cmc.singleton;

/**
 * 工厂模式:定义一个创建类的接口,并让其子类决定实现哪个工厂类,使创建者和调用者分离
 * 简单工厂模式:对于同一等级结构的任一产品,对于新增加的产品需要修改已有代码
 * 工厂方法模式:用来生产同一等级结构中的任一产品,对于新增加的产品支持
 * 抽象工厂模式:用来生产不同产品族的全部产品
 * 
 * 设计步骤:1.定义工厂类
 *          2.定义创建类的接口
 */
/*工厂类*/
class AnimalFactory {
    //工厂接口中只写获取类的方法
    public static Sheep createSheep(){
        return new Sheep() ;
    }
    public static Cow createCow(){
        return new Cow() ;
    }
}

/*接口类*/
interface Animal {
    public void cry() ;
}
/*实现类*/
class Cow implements Animal{

    public void cry() {
        System.out.println("哞哞哞~");
    }
}
class Sheep implements Animal{
    public void cry(){
        System.out.println("咩咩咩~");
    }
} 

public class SimpleFactory {
    public static void main(String[] args) {
        //工厂模式创建对象
        Sheep sheep = AnimalFactory.createSheep() ;
        Cow cow = AnimalFactory.createCow() ;
        sheep.cry();
        cow.cry();

    }
}

工厂方法模式

package com.cn.cmc.factory;

/**
 * 工厂模式:定义一个创建类的接口,并让其子类决定实现哪个工厂类,使创建者和调用者分离
 * 简单工厂模式:对于同一等级结构的任一产品,对于新增加的产品需要修改已有代码
 * 工厂方法模式:用来生产同一等级结构中的任一产品,对于新增加的产品支持
 * 抽象工厂模式:用来生产不同产品族的全部产品
 * 
 * 设计步骤:1.定义工厂类
 *          2.定义创建类的接口
 */
/*工厂类*/
class AnimalFactory {
    //工厂接口中只写获取类的方法
    public static Sheep createSheep(){
        return new Sheep() ;
    }
    public static Cow createCow(){
        return new Cow() ;
    }
}

/*接口类*/
interface Animal {
    public void cry() ;
}
/*实现类*/
class Cow implements Animal{

    public void cry() {
        System.out.println("哞哞哞~");
    }
}
class Sheep implements Animal{
    public void cry(){
        System.out.println("咩咩咩~");
    }
} 

public class SimpleFactory {
    public static void main(String[] args) {
        //工厂模式创建对象
        Sheep sheep = AnimalFactory.createSheep() ;
        Cow cow = AnimalFactory.createCow() ;
        sheep.cry();
        cow.cry();

    }
}

抽象工厂模式

package com.cn.cmc.factory;

public class AbstractFactory {
    /**
     * 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
     *              系统的产品有多于一个的产品族,而系统只消费其中某一族的产品时使用。
     */
    public static void main(String[] args) {
        Engine e = new LuxuryCarFactory().createEngine() ;
        Tyre t = new LuxuryCarFactory().createTyre() ;
        Seat s = new LuxuryCarFactory().createSeat() ;
        e.run();
        e.start();
        t.revolve();
        s.feel();
    }
}

/*高端车生产工厂*/
class LuxuryCarFactory implements CarFactory{

    @Override
    public Seat createSeat() {
        return new LuxurySeat();
    }

    @Override
    public Tyre createTyre() {
        return new LuxuryTyre();
    }

    @Override
    public Engine createEngine() {
        return new LuxuryEngine();
    }
}

/*低端车生产工厂*/
class LowCarFactory implements CarFactory{

    @Override
    public Seat createSeat() {
        return new LowSeat();
    }

    @Override
    public Tyre createTyre() {
        return new LowTyre();
    }

    @Override
    public Engine createEngine() {
        return new LowEngine();
    }
}


/*汽车抽象工厂类*/
interface CarFactory{
    Seat createSeat() ;
    Tyre createTyre() ;
    Engine createEngine() ;
}

/*座椅接口*/
interface Seat{
    void feel() ;
}
/*座椅实现类-高端*/
class LuxurySeat implements Seat{

    @Override
    public void feel() {
        System.out.println("高端座椅十分舒适");
    }
}
/*座椅实现类-低端*/
class LowSeat implements Seat{

    @Override
    public void feel() {
        System.out.println("低端座椅不舒服");
    }
}

/*轮胎接口*/
interface Tyre{
    void revolve() ;
}
/*轮胎实现类-高端轮胎*/
class LuxuryTyre implements Tyre{

    @Override
    public void revolve() {
        System.out.println("高端轮胎不易磨损");
    }
}
/*轮胎实现类-低端轮胎*/
class LowTyre implements Tyre{

    @Override
    public void revolve() {
        System.out.println("低端轮胎易磨损");
    }
}

/*引擎接口*/
interface Engine {
    void run() ;
    void start() ;
}
/*引擎实现类-高端*/
class LuxuryEngine implements Engine{

    @Override
    public void run() {
        System.out.println("高端引擎马力大");
    }

    @Override
    public void start() {
        System.out.println("高端引擎转速快");
    }
}
/*引擎实现类-低端*/
class LowEngine implements Engine{

    @Override
    public void run() {
        System.out.println("低端引擎马力小");
    }

    @Override
    public void start() {
        System.out.println("低端引擎转速慢");
    }

}

工厂模式之间的对比

  • 简单静态工厂模式:虽然不符合设计原则,但用的最多
  • 工厂方法模式:可以通过不修改原有类的前提下实现对类的扩展
  • 抽象工厂模式:不可以增加单个产品,但可以增加产品族,大项目用的多

代理模式

什么是代理模式

为其他对象提供一种代理以控制对这个对象的访问。

使用情况及优缺点

  • 使用情况:想在访问一个类时做一些控制。如安全代理,远程加载,延迟加载
  • 优点:职责清晰、高扩展性、智能化。
  • 缺点:由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。而且实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

代理模式的例子

静态代理

  • 模拟客户找代理买手机
package com.cn.cmc.proxy;

public class StaticProxy {
    public static void main(String[] args) {
        //模拟客户找代理买一台苹果手机
        IPhone iphone = new IPhone() ;
        PhoneProxy phoneproxy = new PhoneProxy(iphone) ;

        phoneproxy.look();
        phoneproxy.tryout();
        phoneproxy.consult();
        phoneproxy.buy();
        phoneproxy.bill();
    }
}

/*手机接口*/
interface Phone {
    public void look();
    public void tryout();
    public void consult() ;
    public void buy() ;
    public void bill() ;
}

/*手机代理类*/
class PhoneProxy implements Phone{

    private Phone phone ;

    public PhoneProxy(Phone phone) {
        super();
        this.phone = phone;
    }

    @Override
    public void look() {
        System.out.println("代理看手机");
    }

    @Override
    public void tryout() {
        System.out.println("代理试用手机");
    }

    @Override
    public void consult() {
        System.out.println("代理咨询手机性能");
    }

    @Override
    public void buy() {
        phone.buy();
    }

    @Override
    public void bill() {
        System.out.println("代理要发票");
    }
}

/*手机类*/

class IPhone implements Phone {

    @Override
    public void look() {
        System.out.println("苹果店里看手机");
    }

    @Override
    public void tryout() {
        System.out.println("苹果店里试用手机");
    }

    @Override
    public void consult() {
        System.out.println("苹果店里咨询手机");
    }

    @Override
    public void buy() {
        System.out.println("苹果店里买手机");
    }

    @Override
    public void bill() {
        System.out.println("苹果店里要发票");
    }

}

动态代理

package com.cn.cmc.proxy;

import java.awt.PageAttributes;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDKDynamicProxy {
    public static void main(String[] args) {
        Phone iphone = new IPhone() ;

        PhoneHandler phonehandler = new PhoneHandler(iphone) ;  
        /*创建一个代理
         * classloader:类加载器
         * class[]:要代理的Class数组
         * handler:代理要实现的Handler
         * */
        Phone proxy = (Phone) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Phone.class}, phonehandler) ;

        proxy.buy();

    }
}

/*手机代理类*/
class PhoneHandler implements InvocationHandler{

    Phone phone ;

    public PhoneHandler(Phone phone) {
        super();
        this.phone = phone;
    }

    /**
     * invoke为调用真正的方法
     * proxy:为在其上调用方法的代理实例
     * method:对应于在代理实例上调用的接口方法的 Method 实例
     * args:包含传入代理实例上方法调用的参数值的对象数组
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理开始买手机");

        if(method.getName().equals("look")){
            phone.look();
        }else if(method.getName().equals("tryout")){
            phone.tryout();
        }else if(method.getName().equals("consult")){
            phone.consult();
        }else if(method.getName().equals("buy")){
            phone.buy();
        }else if(method.getName().equals("bill")){
            phone.bill();
        }else{
            System.out.println("没有此方法");
        }
        System.out.println("代理买手机结束");

        return null;
    }

}

/*手机接口*/
interface Phone {
    public void look();
    public void tryout();
    public void consult() ;
    public void buy() ;
    public void bill() ;
}

/*手机类*/

class IPhone implements Phone {

    @Override
    public void look() {
        System.out.println("苹果店里看手机");
    }

    @Override
    public void tryout() {
        System.out.println("苹果店里试用手机");
    }

    @Override
    public void consult() {
        System.out.println("苹果店里咨询手机");
    }

    @Override
    public void buy() {
        System.out.println("苹果店里买手机");
    }

    @Override
    public void bill() {
        System.out.println("苹果店里要发票");
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值