几种常见的设计模式

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在软件开发中,为了提高软件系统的可维护性和可用性,增加软件的可扩展性和灵活性,开发过程中尽量根据7条原则进行设计,从而提高软件的开发效率、节约软件的开发成本。


提示:以下是本篇文章正文内容,下面案例可供参考

一、设计模式的七大基本原则

  1. 开闭原则:对扩展开放,对修改关闭。对程序功能进行拓展的时候,不能修改原有的代码;
  2. 单一职责原则:一个类只负责一个功能领域相对应的职责;
  3. 里氏替换原则:子类可以扩展父类的功能,但不能修改父类原有的功能。即一个子类不能修改父类原有的方法,只有新增方法;
  4. 依赖倒置原则:面向接口编程,高层模板与底层模板不应该相互依赖。两者应该依赖于各自的抽象;
  5. 接口隔离原则:一个类对另一个类的依赖应该建立在最小的接口上。每一个类都有自己的接口,而不适用单一的总接口;
  6. 迪米特法则(最少知识原则):一个软件实体应该尽可能少的与其他实体发生直接相互作用。例:有三个对象A、B、C。A对象要向C对象发送一个信息,那么A对象并不会直接发送C对象,而是先发送给B对象,然后B对象再把信息发送给C对象;
  7. 合成/聚合复用原则:应该尽可能使用合成、聚合的方式实现代码的复用。不建议使用继承的方式实现代码复用。   继承的缺点:(1)继承破坏了类的封装性。因为继承会将父类的实现细节暴露给子类;(2)子类与父类的耦合度高。当父类修改任何的方法时,子类也要对应进行修改,不利于代码的维护。(3)限制了复用的灵活性。

二、单例模式

什么是单例设计模式:单例模式就是保住在JVM虚拟机内存内一个类只能存在一个实例

以下是单例模式的三种实现方式:

1.饿汉式单例

在加载时就对类进行实例化,占用的内存相对较大

代码如下(示例):

public class Hungry {
    private final static Hungry HUNGRY = new Hungry();
    private Hungry(){};  //单例模式的重点:对构造器进行私有化
    //静态方法调用静态变量
    public static Hungry getInstance(){
        return HUNGRY;
    }
}

2.懒汉式单例

在加载时并不会对类进行实例化,而是在使用的时候进行类的实例化。启动速度快,运行速度相对较慢。

代码如下(示例):

public class Lazy {
    private volatile static Lazy LAZY;  //加上volatile关键字,防止出现指令重排
    private Lazy(){};  //单例模式的重点:对构造器进行私有化
    public static Lazy getInstance(){
        //双重检测锁模式
        if (LAZY == null){
            synchronized (Lazy.class){ //加上锁,防止多线程出现并发问题
                if (LAZY == null){
                    //创建对象不是一个原子性操作,可能出现指令重排,需要在属性上加上volatile
                    LAZY = new Lazy();
                }
            }
        }
        return LAZY;
    }
}

3.内部类实现方式

代码如下(示例):

public class Hodel {
    private Hodel(){} //构造器私有化

    public static Hodel getInstance(){
        return InnerHodel.HODEL;
    }
    private static class InnerHodel{ //内部类
        private static final Hodel HODEL = new Hodel();
    }
}

三、工厂模式

满足创建和使用相分离,即不通过new的方式过去对象实例

1.简单工厂模式

代码如下(示例):

主要是生成同一产品等级的实例

//接口
public interface Cat {
    void name();
}

//五菱宏光的车类
public class WulingCat implements Cat{
    @Override
    public void name() {
        System.out.println("五菱宏光");
    }
}

//特斯拉的车类
public class TesilaCat implements Cat{
    @Override
    public void name() {
        System.out.println("特斯拉");
    }
}
//简单工厂
public class SimpleFactory {
    public static Cat getCat(String name){
        if (name.equals("五菱")){
            return new WulingCat();
        }else if (name.equals("特斯拉")){
            return new TesilaCat();
        }else {
            return null;
        }
    }
}
//用户类,测试
public class Client{
    public static void main(String[] args) {
        Cat wuLing = SimpleFactory.getCat("五菱");
    }
}

2.工厂方法模式

主要是生成同一产品等级的实例

 

代码如下(示例):

//车接口
public interface Cat {
    void name();
}

//五菱宏光类
public class WulingCat implements Cat{
    @Override
    public void name() {
        System.out.println("五菱宏光");
    }
}

//特斯拉类
public class TesilaCat implements Cat{
    @Override
    public void name() {
        System.out.println("特斯拉");
    }
}
//工厂方法接口
public Interface FactoryMethod{
    Cat getCat();
}
//五菱宏光工厂
public class WuLingFactory implements FactoryMethod {
      @Override
      public Cat getCat(){
       return new WuLingCat(); 
    }
}

//特斯拉工厂
public class WuLingFactory implements FactoryMethod {
      @Override
      public Cat getCat(){
       return new TesilaCat(); 
    }
}
//用户类、测试
public class client{
    public static void main(String[] args) {
        //创建特斯拉工厂
        TesilaCatFactory tesilaCatFactory = new TesilaCatFactory();
        //有特斯拉工厂获取特斯拉实例
        Cat tesilaCat = tesilaCatFactory.getCat();
        tesilaCat.name();
    }
}

3.抽象工厂

抽象工厂是生成工厂的工厂,即建立工厂实例。主要是生成多种产品族的实例

 代码如下(示例):

//手机接口
public interface IIpone {
    void name();
}

//路由接口
public Interface IRoute{
    void name();
}

//小米手机
public class XiaoMiIpone implements IIpone{
    @Override
    public void name() {
        System.out.println("是小米手机");
    }
}
//小米路由
public class XiaoMiRoute implements IRoute{
    @Override
    public void name() {
        System.out.println("小米路由器");
    }
}
//华为手机
public class HuaWeiIpone implements IIpone{
    @Override
    public void name() {
        System.out.println("华为手机");
    }
}
//华为路由
public class HuaWeiRoute implements IRoute{
    @Override
    public void name() {
        System.out.println("华为路由器");
    }
}
//抽象工厂的接口
public interface AbstactFactory {
    //手机工厂
    IIpone getIpone();
    //路由器工厂
    IRoute getRoute();
}

//小米工厂
public class XiaoFactory implements AbstactFactory {
    @Override
    public IIpone getIpone() {
        return new XiaoMiIpone();
    }

    @Override
    public IRoute getRoute() {
        return new XiaoMiRoute();
    }
}

//华为工厂
public class HuaWeiFactory implements AbstactFactory {
    @Override
    public IIpone getIpone() {
        return new HuaWeiIpone();
    }

    @Override
    public IRoute getRoute() {
        return new HuaWeiRoute();
    }
}
//用户类、测试
public class client{
    public static void main(String[] args) {
        HuaWeiFactory huaWeiFactory = new HuaWeiFactory();
        IIpone ipone = huaWeiFactory.getIpone();
        IRoute route = huaWeiFactory.getRoute();
        ipone.name();
        route.name();
    }
}

三、观察者模式

观察者模式也称为发布-订阅模式,是一种对象之间一对多的依赖关系,当一个对象状态发生改变时,其他依赖该对象的对象会收到通知,并自动更新状态。

代码如下(示例):

//借款接口
public interface Borrow{
    void brrow(Loans loans);
    void notifys();
}

//贷款接口
public interface Loans{
    void tackMony();
}

//借款人类
public class DibetMan implements Borrow{
    private List<Loans> loansList = new ArrayList<>();
    @Override
    public void brrow(Loans loans) {
        loansList.add(loans);
    }

    @Override
    public void notifys() {
        for (Loans loans :
                loansList) {
            loans.tackMony();
        }
    }
}


//贷款人类
public class LoansMan implements Loans{
    @Override
    public void tackMony() {
        System.out.println("要钱");
    }
}

四、装饰者模式

在不改变原有代码的情况下,动态的给对象增加额外的功能

 代码如下(示例):

//机器人接口
public interface Robot {
    void dosomeThing();
}

//一代机器人
public class OneRobot implements Robot{
    @Override
    public void dosomeThing() {
        System.out.println("唱歌");
    }
}

//二代机器人
public class TowRobot implements Robot{
    private Robot robot;
    public void setRobot(Robot robot){
        this.robot = robot;
    }
   
    @Override
    public void dosomeThing(){
        doMore(); //在一代机器人的基础上新增的功能
        robot.dosomeThing(); //一代机器人的功能
    }

    public void doMore(){
        System.out.println("新增的功能");
    }
}

五、代理模式

在访问的时候并不会直接去访问真实对象,而是通过代理对象去访问

1.静态代理

需要手动创建代理类,每有一个真实对象(被代理类),就需要手动创建一个代理类。代码量翻倍

//被代理类和代理类的公共接口
public interface IHost {
    void rent();
}

//真实对象(被代理类)
public class Host implements IHost{
    @Override
    public void rent(){
    System.out.println("房东出租房子");
    }
}

//代理类
public class Proxy implements IHost{
    private IHost host;
    public void setHost(IHost host){
        this.host = host;
    }
    
    @Override
    public void rent(){
        seeHost(); //代理类新增的功能
        host.rent();
    }
    //代理类新增的功能
    public void seeHost(){
        System.out.println("中介看房");
    }
}
//测试类
public class TestDemo {
    public static void main(String[] args) {
        Proxy proxy = new Proxy();
        proxy.setHost(new Host());
        proxy.rent();

    }
}

2.动态代理

能够自动创建代理类,不需要手动创建代理类。动态代理分为两种:Cglib和Jdk,前者基于类、后者基于接口。动态代理有两个重要的接口(类):Proxy和InvocationHandler。虽然动态代理不需要写代理类,但是需要手动写一个ProxyInvocationHandler(实现InvocationHandler的调用处理程序),并且该类内部聚合代理接口,有可以生成并返回代理类的方法,以及处理代理类实例的方法。

//真实对象接口
public interface Rent {
    void rent();
}

//真实对象(被代理类)
public class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("房东出租房子");
    }
}

//调用处理程序
public class ProxyInvocationHandler implements InvocationHandler {

    private Object target;

    //代理哪一个类就从这里确定的
    public void setTarget(Object target) {
        this.target = target;
    }

    //生成并返回代理类
    public Object getProxy(){
        Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        return proxy;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        seeHost(); //代理类新增的功能
        Object result = method.invoke(target, args);
        return result;
    }
    //代理类新增的功能
    public void seeHost(){
        System.out.println("看房子");
    }
}
//测试
public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        //创建调用处理程序对象
        ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
        //传入被代理类,从而确定代理对象
        proxyInvocationHandler.setTarget(host);
        //获取代理类
        Rent proxy = (Rent) proxyInvocationHandler.getProxy();
        proxy.rent();
    }
}

总结

以上是本人对这几种设计模式的理解以及一些案例,希望对您有所帮助,有错误之处,请批评指正。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小庄学编程666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值