Day322.设计模式回顾 -Java设计模式

Posted 阿昌喜欢吃黄桃

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day322.设计模式回顾 -Java设计模式相关的知识,希望对你有一定的参考价值。

设计模式

一、七大原则

1、单一职责原则

  • 一个类就管一件事

2、接口隔离原则

  • 一个接口,有他自己的方法;当他的子类实现只需要实现对应只想实现的方法,不应该是全部实现;
  • 接口Interface1拆分为独立的几个接口,让一个类对另一个类的依赖应该建立在最小的接口

image-20210708204318752

3、依赖倒转原则

  • 抽象不应该依赖细节,细节应该依赖抽象

如让一个方法的参数依赖接口,而不是具体的实现类,这样子就可以传入这个接口的实现类,更具有扩展性

image-20210708205513446

4、里氏替换原则

  • 子类中尽量不要重写父类的方法,可以通过聚合,组合,依赖 来解决问题

image-20210708210143525

5、开闭原则

  • 模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)

  • 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。

6、迪米特原则

  • 最少知道原则一个类对自己依赖的类知道的越少越好

  • 耦合的方式很多,依赖,关联,组合,聚合等。

    其中,我们称出现成员变量,方法参数,方法返回值中的类为 直接的朋友

    而出现在局部变量中的类 不是直接的朋友

    也就是说,陌生的类 最好不要以局部变量的形式出现在类的内部。

7、合成复用原则

  • 尽量使用合成/聚合的方式,而不是使用继承

image-20210708212105925


二、单例模式

采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例, 并且该类只提供一个取得其对象实例的方法(静态方法)。

1、饿汉式(静态常量)

  • 构造器私有化 (防止 new )

  • 类的内部创建对象

  • 向外暴露一个静态的公共方法。getInstance

public class Singleton1{
    private Singleton1(){};
    private final static Singleton1 instance = new instance();
    public static getInstance(){
        return instance;
    }
}

优点

  • 写法简单,就是在类装载的时候就完成实例化。
  • 避免了线程同步问题

缺点

  • 内存浪费

  • 无lazy loading 的效果


2、饿汉式(静态代码块)

//饿汉式(静态代码块)
public class Singleton2 {
    private Singleton2(){}
    private final static Singleton2 instance;
    static{
        instance = new Singleton2();
    }
    public static Singleton2 getInstance(){
        return instance;
    }
}

优缺点和上面是一样的。


3、懒汉式(线程不安全)

//懒汉式(线程不安全)
public class Singleton3{
    private Singleton3(){};
    private Singleton3 instance;
    public Singleton3 getInstance(){
        if(instance==null){
            instance = new Singleton3();
        }
        return instance;
    }
}

优点

  • Lazy Loading 的效果,但是只能在单线程下使用

缺点

  • 线程不安全

4、懒汉式(线程安全,同步代码块)

//懒汉式(线程安全,同步代码块)
public class Singleton4 {
    private Singleton4() {
    }

    private static Singleton4 instance;

    public static Singleton4 getInstance() {
        if (instance == null) {
            synchronized (this) {
                instance = new Singleton4();
            }
        }
        return instance;
    }
}

不推荐使用性能差


5、懒汉式(线程安全,同步方法)

//懒汉式(线程安全,同步方法)
public class Singleton5 {
    private Singleton5() { }

    private static Singleton5 instance;

    public static synchronized Singleton5 getInstance() {
        if (instance == null) {
                instance = new Singleton5();
        }
        return instance;
    }
}

不推荐使用性能差


6、双重检查

//双重检查
public class Singleton6 {
    private Singleton6() {
    }

    private static volatile Singleton6 instance;

    public Singleton6 getInstance() {
        if (instance == null) {
            synchronized (this) {
                if (instance == null) {
                    instance = new Singleton6();
                }
            }
        }
        return instance;
    }
}

线程安全,延迟加载,效率较高


7、静态内部类

//静态内部类
public class Singleton7 {
    private Singleton7(){}
    private static class SingletonInstance{
        private static final Singleton7 INSTANCE = new Singleton7();
    }
    public Singleton7 getInstance(){
        return SingletonInstance.INSTANCE;
    }
}

优点

  • 避免了线程不安全,利用静态内部类特点实现延迟加载,效率高

8、枚举

//枚举类
public enum  Singleton8 {
    INSTANCE;
}

推荐使用

三、工厂模式

1、简单(静态)工厂模式

image-20210708214753738

  • 定义了一个创建对象的类,由这个类来封装实例化对象的行为

使用场景

当我们会用到大量的创建某种、某类或者某批对象 时,就会使用到工厂模式.


2、工厂方法模式

定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类

image-20210708215338950


3、抽象工厂模式

  • 定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类

  • 可以将简单工厂模式工厂方法模式进行整合

  • 将工厂抽象成两层,AbsFactory(*抽象工厂*) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。

image-20210708215732640

创建对象实例时,不要直接 new 类, 而是把这个 new 类的动作放在一个工厂的方法中,并返回。有的书上说, 变量不要直接持有具体类的引用

四、原型模式

孙大圣拔出猴毛, 变出其它孙大圣

  • 用原型实例指定创建对象的种类,并且通过拷贝克隆这些原型,创建新的对象

image-20210708215945111

代码演示:

image-20210708220046766

五、建造者模式

  • 抽象建造的过程,让具体的实现类去实现各自的建造过程

image-20210708220306676

  • Product(产品角色)

一个具体的产品对象。

  • Builder(抽象建造者)

创建一个 Product 对象的各个部件指定的 接口**/**抽象类。

  • ConcreteBuilder(具体建造者)

实现接口,构建和装配各个部件。

  • Director(指挥者)

构建一个使用 Builder 接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。

六、适配器模式

  • 将一个类的接口转换成另一种接口.让原本接口不兼容的类可以兼容

image-20210708220550638

  • 类适配器模式

通过类继承

image-20210708221024839

  • 对象适配器模式

通过成员变量聚合关系实现

image-20210708221018715

  • 接口适配器模式

通过一个中间抽象类来空实现,然后子类之间继承中间抽象类,对自己需要实现的方法实现

image-20210708220933342

  • 类适配器:以类给到,在 Adapter 里,就是将 src 当做类,继承
  • 对象适配器:以对象给到,在 Adapter 里,将 src 作为一个对象,持有(组合、聚合)
  • 接口适配器:以接口给到,在 Adapter 里,将 src 作为一个接口,实现

七、桥接模式

  • 实现与抽象放在两个不同的类层次中,使两个层次可以独立改变。

image-20210708221344847

//品牌接口
public interface Brand { 
    void open();
    void close(); 
    void call();
}

桥接类聚合了品牌接口类,然后在构造器中传入具体的品牌实现类,在具体的方法做品牌里面的方法调用

image-20210708221417799

实现了抽象和实现部分的分离,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,这有助于系统进行分层设计,从而产生更好的结构化系统

八、装饰者模式

  • 套娃模式,直接new放构造器里面套把抽象类聚合到它的子类里 该子类(装饰者)构造抽象类的实现(被装饰者)

  • 动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则**(ocp**)

image-20210708222049385

代码实现

image-20210708222108469

image-20210708222127022

image-20210708222222133

九、组合模式

  • 它创建了对象组的树形结构,将对象组合成树状结构以表示“整体-部分”的层次关系
  • 通过组织结构管理,下面的例子采用了 集合管理

image-20210708222436012

代码实现

public abstract class OrganizationComponent { 
    private String name; // 名 字
    private String des; // 说 明

    protected	void add(OrganizationComponent organizationComponent) {
        //默认实现
        throw new UnsupportedOperationException();
    }

    protected	void remove(OrganizationComponent organizationComponent) {
        //默认实现
        throw new UnsupportedOperationException();
    }

    //构造器
    public OrganizationComponent(String name, String des) { 
        super();
        this.name = name; this.des = des;
    }

    public String getName() { 
        return name;
    }
    
    public void setName(String name) { 
        this.name = name;
    }

    public String getDes() {
        return des;
    }

    public void setDes(String des) { 
        this.des = des;
    }
    //方法 print,  做成抽象的,  子类都需要实现
    protected abstract void print();
}

image-20210708222905896

image-20210708222919758

image-20210708222933128

public class Client {
    public static void main(String[] args) {
        //从大到小创建对象 学校
        OrganizationComponent university = new University("清华大学", " 中国顶级大学 ");

        //创建 学院
        OrganizationComponent computerCollege = new College(" 计 算 机 学 院 ", " 计 算 机 学 院 "); OrganizationComponent infoEngineercollege = new College("信息工程学院", " 信息工程学院 ");
        //创建各个学院下面的系(专业)
        computerCollege.add(new Department("软件工程", " 软件工程不错 ")); 
        computerCollege.add(new Department("网络工程", " 网络工程不错 "));
        computerCollege.add(new Department("计算机科学与技术", " 计算机科学与技术是老牌的专业 "));
        infoEngineercollege.add(new Department("通信工程", " 通信工程不好学 "));
        infoEngineercollege.add(new Department("信息工程", " 信息工程好学 "));

        //将学院加入到 学校
        university.add(computerCollege); 
        university.add(infoEngineercollege);
        //university.print(); 
        infoEngineercollege.print();
    }
}

需要遍历组织机构,或者处理的对象具有树形结构时, 非常适合使用组合模式.

要求较高的抽象性,如果节点和叶子有很多差异性的话,比如很多方法和属性都不一样,不适合使用组合模式

十、外观模式

  • 外观类就是总控开关,去管理聚合的所有类

  • 解决多个复杂接口带来的使用困难,起到简化用户操作的作用

image-20210708223208692

代码

  • 外观类

集合了需要使用的类,和方法,用户只需要调用这个类的某个方法即可

public class HomeTheaterFacade {
    //定义各个子系统对象,聚合关系
    private TheaterLight theaterLight; 
    private Popcorn popcorn;
    private Stereo stereo; 
    private Projector projector; 
    private Screen screen;
    private DVDPlayer dVDPlayer;

    //构造器
    public HomeTheaterFacade() { 
        super();
        this.theaterLight = TheaterLight.getInstance(); 
        this.popcorn = Popcorn.getInstance(); 
        this.stereo = Stereo.getInstance();
        this.projector = Projector.getInstance();
        this.screen = Screen.getInstance(); 
        this.dVDPlayer = DVDPlayer.getInstanc();
    }

    //操作分成 4  步
    public void ready() { 
        popcorn.on(); 
        popcorn.pop(); 
        screen.down(); 
        projector.on(); 
        stereo.on(); 
        dVDPlayer.on(); 
        theaterLight.dim();
    }

    public void play() { 
        dVDPlayer.play();
    }

    public void pause() { 
        dVDPlayer.pause();
    }

    public void end() { 
        popcorn.off();
        theaterLight.bright(); 
        screen.up(); 
        projector.off(); 
        stereo.off(); 
        dVDPlayer.off();
    }
}

外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性

在维护一个遗留的大型系统时,可能这个系统已经变得非常难以维护和扩展,此时可以考虑为新系统开发一个Facade 类,来提供遗留系统的比较清晰简单的接口,让新系统与 Facade 类交互,提高复用性

十一、享元模式

  • 需要的网站结构相似度很高,而且都不是高访问量网站,如果分成多个虚拟空间来处理,相当于一个相同网站的实例对象很多,造成服务器的资源浪费

  • 运用共享技术有效地支持大量细粒度的对象

  • 避免重新创建,如果没有我们需要的,则创建一个

image-20210708223639374

内部状态 指 :对象共享出来的信息,存储在享元对象内部且不会随环境的改变而改变

外部状态 指 :对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态


代码

// 网站工厂类,根据需要返回压一个网站
public class WebSiteFactory {
    //集合, 充当池的作用
    private HashMap<String, ConcreteWebSite> pool = new HashMap<>();
    //根据网站的类型,返回一个网站, 如果没有就创建一个网站,并放入到池中,并返回
    public WebSite getWebSiteCategory(String type) { 
        if(!pool.containsKey(type)) {
            //就创建一个网站,并放入到池中
            pool.put(type, new ConcreteWebSite(type));
        }
        return (WebSite)pool.get(type);
    }

    //获取网站分类的总数 (池中有多少个网站类型) 
    public int getWebSiteCount() {
        return pool.size();
    }
}
public class Client {
    public static void main(String[] args) {
        // 创建一个工厂类
        WebSiteFactory factory = new WebSiteFactory();
        // 客户要一个以新闻形式发布的网站
        WebSite webSite1 = factory.getWebSiteCategory("新闻");
        webSite1.use(new User("tom"));
        // 客户要一个以博客形式发布的网站
        WebSite webSite2 = factory.getWebSiteCategory("博客");
        webSite2.use(new User("jack"));
        // 客户要一个以博客形式发布的网站
        WebSite webSite3 = factory.getWebSiteCategory("博客");
        webSite3.use(new User("smith"));
        // 客户要一个以博客形式发布的网站
        WebSite webSite4 = factory.getWebSiteCategory("博客");
        webSite4.use(new User("阿昌"));
        System.out.println("网站的分类共=" + factory.getWebSiteCount());
    }
}
//具体网站
public class ConcreteWebSite extends WebSite {
    //共享的部分,内部状态
    private String type = ""; //网站发布的形式(类型)
    //构造器
    public ConcreteWebSite(String type) {
        this.type = type;
    }
    @Override
    public void use(User user) {
        System.out.println("网站的发布形式为:" + type + " 在使用中 .. 使用者是" + user.getName());
    }
}
@Data
public class User {
    private String name;
    
    public User(String name) {
        super();
        this.name = name;
    }
}
public abstract class WebSite {
    public abstract void use(User user);//抽象方法
}

享元模式大大减少了对象的创建,降低了程序内存的占用,提高效率

享元模式提高了系统的复杂度。需要分离出内部状态和外部状态,而外部状态具有固化特性,不应该随着内部状态的改变而改变,这是我们使用享元模式需要注意的地方.

使用享元模式时,注意划分内部状态和外部状态,并且需要有一个工厂类加以控制。

明天继续

以上是关于Day322.设计模式回顾 -Java设计模式的主要内容,如果未能解决你的问题,请参考以下文章

day05-知识回顾

day40-Spring 01-上次课内容回顾

day4 复习回顾

day8--socketserver回顾

day06_01 上节回顾

day9--回顾