设计模式学习

- 1.什么是设计模式:

设计模式是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性。

- 2.软件设计七大原则:

1.开闭原则:当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求。
2.里氏替换原则:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。
3. 依赖倒置原则:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象(其核心思想是:要面向接口编程,不要面向实现编程。
4.单一职责原则:规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分。
5.接口隔离:要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
6.迪米特法则: 如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。
7:合成复用原则:它要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

- 3.模式分类:

1.创建型模式::关注点是“怎样创建对象?”,它的主要特点是“将对象的创建与使用分离”。
分类:单例模式、原型模式、工厂方法抽象工厂模式:建造者模式。
2.结构型模式:描述如何将类或者对象结合在一起形成更大的结构。
分类:代理模式 适配器模式、桥接)模式、装饰模式、外观模式、享元模式、组合模式
3. 行为型模式:描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务。
分类:模板方法模式、策略模式、命令模式、职责链模式、状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式、解释器模式。
4. 模板方法模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。

- 4.常见的几种设计模式:

1、单例模式

定义

  • 指一个类只有一个实例,且该类能自行创建这个实例的一种模式。

特点:

  • 单例类只有一个实例对象;

  • 该单例对象必须由单例类自行创建;

  • 单例类对外提供一个访问该单例的全局访问点。

    优点:

  • 单例模式可以保证内存里只有一个实例,减少了内存的开销。

  • 可以避免对资源的多重占用。

  • 单例模式设置全局访问点,可以优化和共享资源的访问。

    应用场景

  • 对于 Java 来说,单例模式可以保证在一个 JVM 中只存在单一实例。单例模式的应用场景主要有以下几个方面。

  • 需要频繁创建的一些类,使用单例可以降低系统的内存压力,减少 GC。 某类只要求生成一个对象的时候,如一个班中的班长、每个人的身份证号等

  • 某些类创建实例时占用资源较多,或实例化耗时较长,且经常使用。

  • 某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。 频繁访问数据库或文件的对象。

  • 对于一些控制硬件级别的操作,或者从系统上来讲应当是单一控制逻辑的操作,如果有多个实例,则系统会完全乱套。

  • 当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如
    Web中的配置对象、数据库的连接池等。

    代码实现

public class Sigleton {
    
    //创建实例
    private static volatile Sigleton instance;
    //构造方法私有化
    private Sigleton() {
    }
    //提供外部可获取的方法。
    public static Sigleton getInstance() {
        if (null == instance) {
            instance = new Sigleton();
        }
        return instance;
    }
}
2、工厂模式
     **定义**
定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中
   	 **优点:**
  • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
  • 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特。
  • 法则、依赖倒置原则和里氏替换原则。

应用场景:

  • 客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
  • 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
  • 客户不关心创建产品的细节,只关心产品的品牌。

代码实现:
1.有一个医院接口

  public interface Hospital {
    void count();
}

2.医院下面有很多医院,医院的统计方式等记录是不一样,所以需要分别实现。

public class BeijingHospotal implements Hospital {
    @Override
    public void count() {
         //北京医院的统计方式
         System.out.println("北京医院统计结果");
    }
}
public class ShangHaiHospital implements Hospital {
    @Override
    public void count() {
        //上海医院的统计方式
        System.out.println("上海医院统计结果");
    }
}

医院工厂,只有一个任务,根据code,创建响应的医院实例。

public class HospitalFactory {
    public Hospital getHospital(String hospitalCode) {
        if (null == hospitalCode) return null;
        switch (hospitalCode) {
            case "shanghai":
                return new ShangHaiHospital();
            case "beijing":
                return new BeijingHospotal();
            default:
                return null;
        }

    }
}

客户端

    public static void main(String[] args) {
         HospitalFactory factory=new HospitalFactory();
         Hospital hospital=factory.getHospital("shanghai");
         hospital.count();
    }
}

在这里插入图片描述
思考:

   BeijingHospotal beijingHospotal=new BeijingHospotal();
    beijingHospotal.count();

    ShangHaiHospital shangHaiHospital=new ShangHaiHospital();
    shangHaiHospital.count();

我可以这样写也可以,为什么非要加一个工厂类:
1.迪米特法则,又称最少知道原则(Demeter Principle)
最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

作为功能使用者,不想关注怎么实现的,即使实现了发生了很大的变化,都跟我没啥关系,我只跟工厂打交道。

开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。
即使代码怎么拓展,那都是实现者的事情,跟使用者没啥关系。工厂就做了起了这个作用。

3、代理模式

定义:
由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适 合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

1、抽象主题

public interface Ticket {

     void buyTicket();
}

2、真实主题
public class MyTicket implements Ticket {
private String date;
private String destination;

    public MyTicket(String date, String destination) {
        this.date = date;
        this.destination = destination;
    }

    @Override
    public void buyTicket() {
        System.out.println(date+destination);
    }
    
}

3、代理

public class ProxyTicket implements Ticket{
    private MyTicket ticket;
    private String date;
    private String destination;

    public ProxyTicket(String date, String destination) {
        this.date = date;
        this.destination = destination;
    }

    @Override
    public void buyTicket() {
         if(null==ticket){
             ticket=new MyTicket(date,destination);
         }
        ticket.buyTicket();
    }
}

4、客户端

public class ProxyTicketTest {
    public static void main(String[] args) {
          ProxyTicket proxyTicket=new ProxyTicket("2.21","北京");
          proxyTicket.buyTicket();
    }
}

思考:
为什么不直接这样写呢?

public class ProxyTicketTest {
    public static void main(String[] args) {
         
          MyTicket ticket=new MyTicket("2.21","北京");
          ticket.buyTicket();
    }
}

代理模式要解决的就是不能直接访问的问题,需要才需要一个中间层。

适配器模式:
定义:
将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
1.目标接口

public interface Power {
     void  charge();
}

1.适配者1

public class Power110V {

    void charge110V(){
        System.out.println();
    }
}

2.适配器1

public class Power110VAdapter implements Power {

    private Power110V power110V;

    public Power110VAdapter(){
        power110V=new Power110V();
    }
    @Override
    public void charge(){
        power110V.charge110V();
    }
}

适配者2

public class Power220V {
    void charge220V(){
        System.out.println();
    }
}

适配器2

public class Power220VAdapter implements Power {

    private Power220V power220V;

    public Power220VAdapter() {
        power220V = new Power220V();
    }

    @Override
    public void charge() {
        power220V.charge220V();
    }
}

客户端:

public class PowerTest {
    public static void main(String[] args) {
         Power power=new Power110VAdapter();
         power.charge();
    }
}

对于客户端来说,只需要调用charge就可以,即转换成客户希望的接口

4、装饰者模式:

定义:
指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。

优点:
装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
装饰器模式完全遵守开闭原则
抽象构件

public interface Car {
    void run();
}

具体构件(ConcreteComponent)角色

public class Taxi implements Car {

    @Override
    public void run() {
       //拉人
    }
}

抽象装饰(Decorator)角色:
继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能

public class Decorator implements Car{
    protected Car decoratedCar;

    public Decorator(Car decoratedCar) {
        this.decoratedCar = decoratedCar;
    }

    @Override
    public void run() {
        decoratedCar.run();
    }
}

具体装饰(ConcreteDecorator)角色:
实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

public class TaxiDecorator extends Decorator {
    protected Car decoratedCar;

    public TaxiDecorator(Car decoratedCar) {
        super(decoratedCar);
    }

    @Override
    public void run() {
        decoratedCar.run();
        freight();
    }

    public void freight(){
        //拉货
    }
}

客户端:

public class TaxiDecoratorTest {
    public static void main(String[] args) {
         TaxiDecorator taxi=new TaxiDecorator(new Taxi());
         taxi.freight();
    }
}

可以用子类实现,装饰器模式比子类灵活。

5、观察者模式

定义
指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

优点:
降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
目标与观察者之间建立了一套触发机制。
抽象目标

public abstract class Subject {
    protected List<Observer> observers = new ArrayList<Observer>();
    //增加观察者方法
    public void add(Observer observer) {
        observers.add(observer);
    }
    //删除观察者方法
    public void remove(Observer observer) {
        observers.remove(observer);
    }
    public abstract void notifyObserver(); //通知观察者方法
}

具体目标

public class RedPilotLamp extends Subject {
    @Override
    public void notifyObserver() {
         for(Observer observer:observers){
             observer.response();
         }
    }
}

抽象观察者

public interface Observer {

    void response();
}

具体观察者

public class Bus implements Observer {
    @Override
    public void response() {
          System.out.println("bus停车");
    }
}
public class Taxi implements Observer {
    @Override
    public void response() {
         System.out.println("Taxi停车");
    }
}

客户端

public class ObseverModeTest {
    public static void main(String[] args) {
        Subject pilotLamp=new RedPilotLamp();
        Bus bus=new Bus();
        Taxi taxi=new Taxi();
        pilotLamp.add(bus);
        pilotLamp.add(taxi);
        pilotLamp.notifyObserver();
    }

在这里插入图片描述

策略模式“
定义:
该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理

优点:
1、多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句,如 if…else 语句、switch…case 语句。
2、策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
3、策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
4、策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
5、策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。

抽象策略类

public interface Strategy {
    int doOperation(int i,int j);
}

具体策略A

public class AddStrategy implements Strategy {
    @Override
    public int doOperation(int i, int j) {
        return i+j;
    }
}

具体策略B

public class SubtractionStrategy implements Strategy {
    @Override
    public int doOperation(int i, int j) {
        return i-j;
    }
}

环境类:

public class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public int doOperation(int i, int j) {
        return strategy.doOperation(i, j);
    }
}

测试

public class TestStrategy {
    public static void main(String[] args) {
        Context context = new Context(new AddStrategy());
        int result = context.doOperation(1, 7);
        System.out.println(result);
    }

参考:
http://c.biancheng.net/view/1359.html
https://www.runoob.com/design-pattern/decorator-pattern.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值