Java设计模式Ⅳ
1.装饰者模式
1.1 装饰者模式概述
(1)基本介绍
①装饰者模式:动态的将新功能附加到对象上,在对象功能扩展方面,它
比继承更有弹性,也体现出了开闭原则
(2)分析图
PS:java的IO结构FilterInputStream就是用的装饰者模式
1.2 代码理解
1.Drink类
package com.pattern.设计模式.装饰者模式;
public abstract class Drink {
public String des;
private Float price = 0.0F;
public Drink() {
}
public Drink(String des, Float price) {
this.des = des;
this.price = price;
}
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
@Override
public String toString() {
return "Drink{" +
"des='" + des + '\'' +
", price=" + price +
'}';
}
// 计算费用的方法
// 定义成一个抽像方法,让子类去实现它
public abstract float cost();
}
2.Decorator类
package com.pattern.设计模式.装饰者模式;
public class Decorator extends Drink{
private Drink drink;
public Decorator(Drink drink){
this.drink = drink;
}
@Override
public float cost() {
// 这里拿到调料自己的价格 + 咖啡的价格
return super.getPrice() + drink.cost();
}
@Override
public String getDes() {
// 拿到自己的信息 + 价格 再去拿到咖啡的信息
return super.des + " " + super.getPrice() + "&&" + drink.getDes();
}
}
3.Coffee类
package com.pattern.设计模式.装饰者模式;
public class Coffee extends Drink {
@Override
public float cost() {
return super.getPrice();
}
}
4.继承Coffee的子类,可以自行添加(这里就写一个例子)
package com.pattern.设计模式.装饰者模式;
public class ShortBlack extends Coffee{
public ShortBlack(){
setDes("shortBlack");
setPrice(4.0F);
}
}
5.继承Decorator的子类 同上
package com.pattern.设计模式.装饰者模式;
public class Soy extends Decorator{
public Soy(Drink drink) {
super(drink);
setDes("豆浆");
setPrice(2.0F);
}
}
6.测试类(牛奶等等可自行添加)
package com.pattern.设计模式.装饰者模式;
public class Test {
public static void main(String[] args) {
// 下单2份牛奶 + 一份豆浆的ShortBlack
// 1.点一份ShortBlack
Drink drink = new ShortBlack();
System.out.println(drink);
// 加如一份豆浆
drink = new Soy(drink);
System.out.println(drink);
System.out.println(drink.cost());
// 加入一份牛奶
drink = new Milk(drink);
System.out.println(drink);
System.out.println(drink.cost());
// 再加一份牛奶
drink = new Milk(drink);
System.out.println(drink);
System.out.println(drink.cost());
}
}
2.组合模式
2.1 组合模式概述
(1)基本介绍
①它又称部分整体模式,他创建了对象组的树形结构,将对象组合成
树状结构以表示 整体-部分 的层次关系
②组合模式依据树形结构来组合对象,用来表示部分以及整体的层次
③属于结构性设计模式
④组合模式使得用户对单个对象和组合对象得访问具有一致性,即:
组合能让客户以一致性的方式处理个别对象以及组合对象
(2)类图理解
PS:组合模式在JDK的HashMap中使用到了
(3)组合模式的注意事项和细节
1.简化客户端操作,客户端只需要面对一致的对象而不用考虑整体部分
或者节点叶子的问题
2.具有较强的扩展性,当我们需要该组合对象时,我们只需要调整内部的
层次关系, 客户端不需要做出任何改动
3.方便创建出复杂的层次结构,客户端不用理会组合里面的组成细节,
容易添加节点或者叶子从而创建出复杂的树形结构
4.需要遍历组织机构,或者处理的对象具有树形结构时,非常适合
使用组合模式
5.要求较高的抽象性,如果节点和叶子有很多差异性的话,不适合
使用组合模式
2.2 代码理解
1.OrganizationComponent类
package com.pattern.设计模式.组合模式;
public abstract class Component {
private String name;
private String des;
protected void add(Component component){
// 默认实现
}
protected void remove(Component component){
}
// 抽象方法 继承的子类都需要实现
protected abstract void print();
// 构造器
public Component(){
}
public Component(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;
}
@Override
public String toString() {
return "Component{" +
"name='" + name + '\'' +
", des='" + des + '\'' +
'}';
}
}
2.Department类
package com.pattern.设计模式.组合模式;
public class Department extends Component{
public Department() {
}
public Department(String name, String des) {
super(name, des);
}
@Override
public String getName() {
return super.getName();
}
@Override
public String getDes() {
return super.getDes();
}
@Override
protected void print() {
System.out.println("<><><>" + getName() + "<><><>");
}
}
3.College类
package com.pattern.设计模式.组合模式;
import java.util.ArrayList;
import java.util.List;
public class College extends Component{
List<Component> list = new ArrayList<Component>();
public College() {
}
public College(String name, String des) {
super(name, des);
}
@Override
protected void add(Component component) {
list.add(component);
}
@Override
protected void remove(Component component) {
list.remove(component);
}
@Override
public String getName() {
return super.getName();
}
@Override
public String getDes() {
return super.getDes();
}
@Override
protected void print() {
System.out.println("<<>>" + getName() + "<><>");
for (Component component : list) {
component.print();
}
}
}
4.University类
package com.pattern.设计模式.组合模式;
import java.util.ArrayList;
import java.util.List;
public class University extends Component{
List<Component> list = new ArrayList<Component>();
public University() {
}
// 构造器
public University(String name, String des) {
super(name, des);
}
// 重写add方法
@Override
protected void add(Component component) {
list.add(component);
}
@Override
protected void remove(Component component) {
list.remove(component);
}
@Override
public String getName() {
return super.getName();
}
@Override
public String getDes() {
return super.getDes();
}
@Override
protected void print() {
System.out.println(">>>>" + getName() + "<<<<<");
for (Component component : list) {
component.print();
}
}
}
5.测试类
package com.pattern.设计模式.组合模式;
public class Test {
public static void main(String[] args) {
// 从大到小创建对象
// 创建大学
Component university = new University("北大", "China");
// 创建学院
Component component = new College("计算机学院", "软件工程");
Component component1 = new College("天文学学院", "看星星");
// 创建计算机学院的系
component.add(new Department("软件工程", "敲代码"));
component.add(new Department("计算机应用", "边敲代码边焊电"));
component.add(new Department("网络工程", "网络工程"));
// 创建天文学学院的系
component1.add(new Department("天文学", "看不完的星星"));
// 将学院加入到 学校
university.add(component);
university.add(component1);
university.print();
}
}
3.外观模式
3.1 外观模式概述
(1)基本介绍
①外观模式也叫过程模式,外观模式为子系统中的一组接口提供一个
一致的界面。此模式定义了一个高级接口,这个接口使得这一子
系统更加容易使用
②外观模式通过定义一个一致的接口,用已屏蔽内部子系统的细节,
使得调用端跟这个接口发生调用,则无需关心这个子系统的内部细节
(2)原理类图
(3)Mybatis中的Configuration去创建MetaObject对象使用到了外观模式
(4)外观模式的注意事项和细节
1.外观模式对外屏蔽了子系统的细节,因此降低了客户端对子系统
使用的复杂性
2.外观模式客户端与子系统的耦合关系,让子系统内部的模块更易于
维护和扩展
3.通过合理的使用外观模式,可以帮我们更好的划分访问层次
4.当系统需要进行分层设计时,可以考虑使用外观模式
5.在维护一个遗留的大型系统时,可能这个系统已经变得难以维护和
扩展,此时可以考虑为新系统开发一个外观类,来提供遗留系统的
比较清晰简单的接口,让系统与外观类交互,提高复用性
6.不能过多的或者不合理的使用外观模式,使用外观模式好,还是
直接调用模块好,要以让系统有层次,利于维护为目的。
3.2 代码理解
1.子系统类例子代码(自行增加即可)
package com.pattern.设计模式.外观模式;
public class DVDPlayer {
// 使用单例模式 恶汉式
private static DVDPlayer dvdPlayer = new DVDPlayer();
public static DVDPlayer getInstance(){
return dvdPlayer;
}
// 打开功能
public void open(){
System.out.println("DVD打开了");
}
// 关闭
public void close(){
System.out.println("DVD关闭");
}
// 播放
public void play(){
System.out.println("DVD播放");
}
// 暂停
public void stop(){
System.out.println("DVD暂停");
}
}
2.客户端类
package com.pattern.设计模式.外观模式;
public class HomeTheaterFaced {
// 定义各个子系统
private TheaterLight theaterLight;
private Popcorn popcorn;
private DVDPlayer dvdPlayer;
private Screen screen;
private Stereo stereo;
private Projector projector;
public HomeTheaterFaced() {
this.theaterLight = TheaterLight.getInstance();
this.popcorn = Popcorn.getInstance();
this.dvdPlayer = DVDPlayer.getInstance();
this.screen = Screen.getInstance();
this.stereo = Stereo.getInstance();
this.projector = Projector.getInstance();
}
public void getMake(){
popcorn.open();
popcorn.pop();
screen.open();
projector.open();
stereo.open();
dvdPlayer.open();
theaterLight.open();
}
public void play(){
dvdPlayer.play();
}
public void stop(){
dvdPlayer.stop();
}
public void end(){
popcorn.close();
screen.close();
projector.close();
stereo.close();
dvdPlayer.close();
theaterLight.close();
}
}
3.测试类
package com.pattern.设计模式.外观模式;
public class Test {
public static void main(String[] args) {
HomeTheaterFaced homeTheaterFaced = new HomeTheaterFaced();
homeTheaterFaced.getMake();
homeTheaterFaced.play();
homeTheaterFaced.stop();
homeTheaterFaced.end();
}
}
4.享元模式
4.1 享元模式概述
(1)基本介绍
①享元(Flyweight)模式也叫蝇量模式,运用共享技术有效的支持大量
细粒度的对象
②常用于系统底层开发,解决系统的性能问题,比如数据库连接池,
里面都是创建好的连接对象,在这些连接对象中有我们需要的则
直接拿来用,避免重新创建,如果我们需要,则创建一个
③享元模式能解决重复对象的内存浪费问题,当系统中有大量相似
对象,需要缓冲池时,不需要总是创建对象,可以冲缓冲池拿,
这样可以降低系统内存,同时提高效率
④享元模式经典的应用场景就是池技术,Stirng常量池,数据库
连接池,缓冲池等等都是享元模式的应用,享元模式是池技术
的重要实现方式
(2)介绍扩展–内部状态和外部状态
1.享元模式提出了两个要求,细粒度和共享对象,涉及到内部状态和
外部状态,即:将对象的信息分为两个部分,内部状态和外部状态
2.内部状态:指对象共享出来的信息,存储在享元对象内部且不会随
环境的改变而改变
3.外部状态:指对象得以依赖的一个标记,是随环境改变为改变的,
不可共享的状态
(3)类图
(4)JDK中,Integer源码就是用到了享元模式
(5)享元模式注意事项和细节
1.享元模式可以这样理解:享就是共享,元就是对象
2.系统中有大量对象,这些对象消耗大量内存,并且对象的状态大部分
可以外部化时,我们就可以考虑选用享元模式
3.用唯一标识码判断,如果内存中有,则返回这个唯一标识码所标识的
对象,用HashMap / HashTable存储
4.享元模式大大减少了对象的创建,降低了程序内存占用,提高效率
5.享元模式提高了系统的复杂度,需要分离出内部状态和外部状态,
而外部状态具有固化特性,不应该随着内部状态改变而改变,这
是我们使用享元模式需要注意的地方
6.使用享元模式时,注意划分内部状态和外部状态,并且需要一个
共产类加以控制
7.享元模式经典使用场景有:String常量池,数据库连接池
4.2 代码理解
1.WebSiteFactory类
package com.pattern.设计模式.享元模式;
import java.util.HashMap;
public class WebSiteFactory {
// 集合 充当池的作用
private HashMap<String, ConcreteWebSite> hashMap = new HashMap<>();
// 根据网站的类型返回一个网站 如果没有就创建放入池中,并返回
public WebSite getWebSite(String type){
// 如果没有,就创建一个放入池中
if (!hashMap.containsKey(type)){
hashMap.put(type, new ConcreteWebSite(type));
}
return (WebSite) hashMap.get(type);
}
// 获取网站的分类总数
public int getCount(){
return hashMap.size();
}
}
2.WebSite类
package com.pattern.设计模式.享元模式;
public abstract class WebSite {
public abstract void use(User user);
}
3.ConcreteWebSite 类
package com.pattern.设计模式.享元模式;
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() + "在使用它>>>");
}
}
4.java实体类User
package com.pattern.设计模式.享元模式;
public class User {
private String name;
public User() {
}
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
5.测试类
package com.pattern.设计模式.享元模式;
public class Test {
public static void main(String[] args) {
// 创建一个工厂类
WebSiteFactory webSiteFactory = new WebSiteFactory();
// 客户需要一个以新闻形式发布的网站
WebSite webSite = webSiteFactory.getWebSite("新闻");
webSite.use(new User("李白"));
// 以博客形式
WebSite webSite1 = webSiteFactory.getWebSite("博客");
webSite1.use(new User("杜甫"));
// 再建一个以博客形式
WebSite webSite2 = webSiteFactory.getWebSite("博客");
webSite2.use(new User("李清照"));
System.out.println("网站的分类共:" + webSiteFactory.getCount());
}
}