常用设计模式学习(一)

设计模式

这里是对几种常见设计模式进行学习。今天是面试回来复盘,面试官问的很基础,但是很遗憾的是,因为太基础没回答上。。。也是很无奈了。其实复习之后发现设计模式核心只为了三点,一是代码复用,二是解耦合,三是方便扩展,下面围绕这三点去学习几种常见的设计模式。

设计模式(Design Patterns),是一套可以被反复使用,多数人知晓的经过分类编目的,代码设计经验的总结。使用设计模式是为了可重用代码,方便他人理解,保证代码可靠性。
设计模式分三大类:

  • 创建型模式,五种:工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。
  • 结构型模式,七种:适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
  • 行为型模式,十一种:策略模式,模板方法模式,观察者模式,迭代子模式,责任链模式,命令模式,备忘录模式,状态模式,访问者模式,中介者模式,解释器模式。
  • 还有其他两种,并发模式和线程池模式。

设计模式的六大原则

  1. 开闭原则(open close Principle):开闭原则就是对扩展开放,对修改关闭。在程序需要一个新功能的扩展和实现时候,不能去修改原有的代码,为了程序更好的扩展性,我们需要使用接口和抽象类。
  2. 里氏替换原则(Liskov Substitution Principle):面向对象设计的基本原则之一。里氏替换原则中说,任何基类可以出现的地方,其子类也一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
  3. 依赖倒转原则(Dependence Inversion Principle):这个是开闭原则的基础,针对接口编程,依赖于抽象而不依赖于具体。
  4. 接口隔离原则(interface inversion Principle):使用多个隔离的接口,比使用单个接口要好。还是降低类之间的耦合度的意思。
  5. 迪米特法则(最少知道法则):一个实体应当尽量少的于其他实体之间发生相互作用,使得系统功能模块相互独立。
  6. 合成复用原则:原则是尽量使用合成的方式,而不是使用继承。

工厂模式

普通工厂模式

就是建立一个工厂类,对实现同一接口的一些类进行实例的创建。

/**
 * 普通工厂设计模式Demo,角色接口Role
 * @author 安澜
 */
public interface role {

    public void method();
}
/**
 * 普通工厂设计模式Demo,role的实现类student
 * @author 安澜
 */
public class student implements role {
    public void method() {
        System.out.println("this is  "+this.getClass().getSimpleName()+"  of role");
    }
}
/**
 * 普通工厂设计模式Demo,role的实现类teacher
 * @author 安澜
 */
public class teacher  implements role {

    public void method() {
        System.out.println("this is  "+this.getClass().getSimpleName()+"  of role");

    }
}
/**
 * 普通工厂设计模式Demo,工厂类FactoryDesign
 * @author 安澜
 */
public class FactoryDesign {

    public role getRole(String type){
    
        if("teacher".equals(type)){
            return new teacher();
            
        }else if("student".equals(type)){
            return new student();
            
        }else {
            System.out.println("类型输入错误==》"+type);
        }
        
        return null;
    }

}
/**
 * 普通工厂设计模式Demo
 * @author 安澜
 */
public class FactoryTest_One {
    public static void main(String[] args) {
    
        FactoryDesign factory = new FactoryDesign();
        
        role teacher = factory.getRole("teacher");
        teacher.method();
        
        role student = factory.getRole("student");
        student.method();
        
        role aNull = factory.getRole("null");
        aNull.method();
    }
}

this is  teacher  of role
this is  student  of role
类型输入错误==》null
Exception in thread "main" java.lang.NullPointerException
	at com.study.Design.demo.FactoryTest_One.main(FactoryTest_One.java:18)

多个工厂方法模式

对普通工厂模式的改进,在普通工厂模式中如果字符串错误则不能创建对象,而多个工厂模式提供多个工厂方法,分别创建对象。

/**
 * 多个工厂方法模式Demo,工厂类MultipleDactoryMethod
 * @author 安澜
 */
public class MultipleDactoryMethod {
    /**
     * get teacher
     * @return role
     */
    public role getTeacher(){
        return new teacher();
    }

    /**
     * get student
     * @return role
     */
    public role getStudent(){
        return new student();
    }
}
/**多个工厂方法模式Demo
 * @author 安澜
 */
public class FactoryTest_Thre {
    public static void main(String[] args) {

        MultipleDactoryMethod multipleDactoryMethod = new MultipleDactoryMethod();

        role student = multipleDactoryMethod.getStudent();
        student.method();

        role teacher = multipleDactoryMethod.getTeacher();
        teacher.method();
    }
}
this is  student  of role
this is  teacher  of role

静态工厂方法模式

就是将上面多个工厂模式中的方法设置为静态,不需要创建工厂的实例,直接调用即可。

/**
 * 静态工厂方法模式Demo,工厂类StaticDactoryMethod
 * @author 安澜
 */
public class StaticDactoryMethod {
    /**
     * get teacher
     * @return role
     */
    public static role getTeacher(){
        return new teacher();
    }

    /**
     * get student
     * @return role
     */
    public static role getStudent(){
        return new student();
    }
}
/**
 * 静态工厂方法模式Demo
 * @author 安澜
 */
public class FactoryTest_four {
    public static void main(String[] args) {

        role student = StaticDactoryMethod.getStudent();
        role teacher = StaticDactoryMethod.getTeacher();

        student.method();
        teacher.method();
    }
}

抽象工厂模式

工厂模式有一个缺陷,就是类的创建依赖于工厂类,也就是说如果我们需要拓展程序,必须对工厂类进行修改,违背了开闭原则,所以从设计模式的角度考虑,创建一个工厂类接口,让多个工厂类去实现这个接口,这样一旦需要增加新的功能,只需要增加新的工厂类就可以了,避免修改之前的代码。

/**
 * 抽象工厂模式,工厂接口FactoryInterface
 * @author 安澜
 */
public interface FactoryInterface {
    /**
     * get Role
     * @return role
     */
    public role getRole();
}
/**
 * 抽象工厂模式,工厂接口的实现类StudentFactory
 * @author 安澜
 */
public class StudentFactory implements FactoryInterface {
    /**
     * get Role
     * @return role
     */
    public role getRole() {
        return new student();
    }

}
/**
 * 抽象工厂模式,工厂接口的实现类TeacherFactory
 * @author 安澜
 */
public class TeacherFactory implements FactoryInterface {
    /**
     * get Role
     * @return role
     */
    public role getRole() {
        return new teacher();
    }
}
/**
 * 抽象工厂模式,工厂接口的新增实现类PrincipalFactory
 * @author 安澜
 */
public class PrincipalFactory implements FactoryInterface {
    /**
     * get Role
     * @return role
     */
    public role getRole() {
        return new principal();
    }
}
/**
 * 抽象工厂模式Demo
 * @author 安澜
 */
public class FactoryTest_Two {
    public static void main(String[] args) {

        FactoryInterface studentFactory = new StudentFactory();
        FactoryInterface teacherFactory = new TeacherFactory();
        PrincipalFactory principalFactory = new PrincipalFactory();

        role principal = principalFactory.getRole();
        principal.method();
        role stu = studentFactory.getRole();
        stu.method();
        role tea = teacherFactory.getRole();
        tea.method();
    }
}
this is  principal  of role
this is  student  of role
this is  teacher  of role

建造者模式

工厂模式提供的是创建单个类的方法,而建造者模式则是将各种产品集中起来管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性。

/**建造者模式Demo,建造者类BuilderDesign
 * @author 安澜
 */
public class BuilderDesign {

   List<role> roles=new ArrayList<role>();

    /**
     * teacher Builder
     * @param count
     */
    public void teacherBuilder(int count){

        for(int i=1;i<=count;i++){
            roles.add(new teacher());
        }
    }

    /**
     * student Builder
     * @param count
     */
    public void studentBuilder(int count){

        for(int i=1;i<=count;i++){
            roles.add(new student());
        }
    }

    /**
     * principal Builder
     * @param count
     */
    public void principalBuilder(int count){

        for(int i=1;i<=count;i++){
            roles.add(new principal());
        }
    }
}
/**
 * 建造者模式Demo
 * @author 安澜
 */
public class BuilderDemo {
    public static void main(String[] args) {

        BuilderDesign builderDesign = new BuilderDesign();
        builderDesign.principalBuilder(1);
        builderDesign.teacherBuilder(5);
        builderDesign.studentBuilder(20);
    }
}

单例模式

单例模式是一种常见的设计模式,在java应用中,单例对象能保证在一个jvm中,该对象只有一个实例存在。

  1. 避免某些大型对象频繁创建,节省系统开销。
  2. 省去new操作符的使用,降低系统内存的使用频率,减轻GC压力。
  3. 在一些特定的场景下保证核心服务独立控制整个流程。

单例模式的实现——私有构造方法,静态属性

/**这是一个简单的单例类,不能满足多线程环境下的单例模式
 * @author 安澜
 */
public class SingletonClass {

    /**
     * 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载
     */
    private static SingletonClass Instance= null;

    /**
     * 私有构造方法,防止被实例化
     */
    private SingletonClass(){}

    /**
     * 静态工程方法,创建实例
     */
    public static SingletonClass getInstance(){
        return Instance=new SingletonClass();
    }

    /**
     * 如果该对象被用于序列化,可以保证对象在序列化前后保持一致
     */
    public Object readResolve() {
        return Instance;
    }
    
}

单例模式的实现——Synchronized,双重检验

/**SingletonClass With Synchronized,满足多线程环境下的单例模式
 * @author 安澜
 */
public class SingletonClassWithSynchronized {

    /**
     * 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载
     */
    private static SingletonClassWithSynchronized Instance= null;

    /**
     * 私有构造方法,防止被实例化
     */
    private SingletonClassWithSynchronized(){}

    /**
     * 静态工程方法,创建实例
     * 这里使用双重检验防止多线程情景下创建了多个实例
     */
    public static SingletonClassWithSynchronized getInstance(){
        if(Instance==null) {
            synchronized (Instance) {
                if (Instance==null) {
                    return Instance=new SingletonClassWithSynchronized();
                }
            }
        }
        return Instance;
    }

    /**
     * 如果该对象被用于序列化,可以保证对象在序列化前后保持一致
     */
    public Object readResolve() {
        return Instance;
    }
    
}

在Java指令中创建对象和赋值操作是分开进行的,也就是说Instance= new
SingletonClassWithSynchronized();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的SingletonClassWithSynchronized实例分配空间,然后直接赋值给instance成员,然后再去初始化这个SingletonClassWithSynchronized实例。这样就可能出错了,我们以A、B两个线程为例:

a>A、B线程同时进入了第一个if判断

b>A首先进入synchronized块,由于instance为null,所以它执行instance = new SingletonClassWithSynchronized();

c>由于JVM内部的优化机制,JVM先画出了一些分配给SingletonClassWithSynchronized实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。

d>B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。

e>此时B线程打算使用SingletonClassWithSynchronized实例,却发现它没有被初始化,于是错误发生了。

单例模式的实现——静态内部类

/**SingletonClass With Factory,优化synchronized实现单例,满足多线程环境下的单例模式
 * @author 安澜
 */
public class SingletonClassWithFactory {
    
    /**
     * 私有构造方法,防止被实例化
     */
    private SingletonClassWithFactory(){}
    
    /**
     * 私有静态内部工厂类
     */
    private static class SingletonFactory{

        private static SingletonClassWithFactory instance=new SingletonClassWithFactory();

        private static SingletonClassWithFactory getInstance(){

            return SingletonFactory.instance;
        }

    }
    
}

JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。

代理模式

代理模式就是多一个代理类出来,替元对象进行一些操作。

/**代理模式Demo,被代理接口ProxyInterface
 * @author 安澜
 */
public interface ProxyInterface {

    public void method();
}
/**代理模式Demo,元对象ProxyIMPL
 * @author 安澜
 */
public class ProxyIMPL implements ProxyInterface {
	/**
     * 被代理方法method
     */
    public void method() {
        System.out.println("this is proxy method ");
    }
}
/**代理模式Demo,代理类ProxyClass
 * @author 安澜
 */
public class ProxyClass implements ProxyInterface {

    private static ProxyIMPL proxyIMPL=new ProxyIMPL();


    public void method() {
        beforeMethod();
        proxyIMPL.method();
        afterMethod();
    }

    public void beforeMethod(){
        System.out.println("this is before method ");
    }

    public void afterMethod(){
        System.out.println("this is after method ");
    }
public static void main(String[] args) {

        ProxyClass proxyClass = new ProxyClass();
        proxyClass.method();
    }
this is before method 
this is proxy method 
this is after method 

代理模式的应用场景:

如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:

1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。

2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。

使用代理模式,可以将功能划分的更加清晰,有助于后期维护!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值