设计模式之结构型模式
Posted 编程爱好者ing
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之结构型模式相关的知识,希望对你有一定的参考价值。
结构型模式主要有:适配器模式(手机充电案例),桥接模式(各种样式及品牌手机,小米,华为,折叠,直立手机),装饰者模式(星巴克咖啡订单),组合模式(显示学校院系),外观模式,享元模式,代理模式
一、适配器模式
基本介绍:
1)适配器模式就是将某个类的接口转换成客户端期望的另一个接口表示,主要的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为包装类
2)适配器模式主要分为三类:类适配器模式,对象适配器模式,接口适配器模式。
类适配器
类适配器代码:
/**要被适配的电源电压类
* @author admin
*
*/
public class Source {
public int source220v() {
int f=220;
System.out.println("这是"+f+"的电压");
return f;
}
}
/**目标电压接口
* @author admin
*
*/
public interface IReturn5v {
public int return5v();
}
/**中间适配器
* @author admin
*/
public class Exchange extends Source implements IReturn5v {
/**
* 实现接口类方法
*/
@Override
public int return5v() {
int f=source220v();//获取父类220v电压
int adapt=f/44;//中间做的转换过程
return adapt;
}
}
//手机类
public class Phone {
//充电方法,传入手机可以接受的电压
public void charging(IReturn5v return5v) {
if(return5v.return5v()==5) {
System.out.println("可以充电。。。");
}else {
System.out.println("不可以充电。。。");
}
}
}
//测试代码:
public static void main(String[] args) {
//创建手机对象
Phone phone=new Phone();
//手机充电,传入适配器对象,使其返回5V电压给手机充电
phone.charging(new Exchange());
}
对象适配器:
UML图:
对象适配器代码,phone和接口代码与类适配器代码相同,略过
适配器修改后的代码
/**中间适配器
* @author admin
*将source作为适配器的属性传入
*/
public class Exchange implements IReturn5v {
private Source source;
public Exchange(Source source) {
this.source = source;
}
/**
* 实现接口类方法
*/
@Override
public int return5v() {
int f=source.source220v();//获取父类220v电压
int adapt=f/44;//中间做的转换过程
return adapt;
}
}
测试代码:
public static void main(String[] args) {
Phone phone=new Phone();
//创建适配器对象的时候传入source对象
phone.charging(new Exchange(new Source()));
}
接口适配器模式:
当一个接口有m1,m2,m3等多个方法是,如果此时B类只需要使用接口中m1方法,不需要m2,m3方法。这个时候,可以使用一个抽象类A去实现接口的所有方法。即空实现接口中所有方法。然后匿名内部类重写A类的m1方法即可。这就是接口适配器模式。
代码如下:
//接口
public interface ISource {
public void m1();
public void m2();
public void m3();
public void m4();
}
/**空实现接口方法
* @author admin
*
*/
public abstract class Abs implements ISource {
@Override
public void m1() {
}
@Override
public void m2() {
}
@Override
public void m3() {
}
@Override
public void m4() {
}
}
//测试类
public static void main(String[] args) {
//使用匿名内部类重写m1方法即可
Abs abs=new Abs() {
public void m1() {
System.out.println("重写抽象类m1方法。。。");
}
};
abs.m1();
}
二、桥接模式
桥接模式简介
UML类图:
//品牌接口
public interface Brand {
void open();
void close();
void call();
}
//vivo手机
public class Vivo implements Brand {
@Override
public void open() {
System.out.println(" Vivo手机开机 ");
}
@Override
public void close() {
System.out.println(" Vivo手机关机 ");
}
@Override
public void call() {
System.out.println(" Vivo手机打电话 ");
}
}
//小米手机
public class XiaoMi implements Brand {
@Override
public void open() {
System.out.println(" 小米手机开机 ");
}
@Override
public void close() {
System.out.println(" 小米手机关机 ");
}
@Override
public void call() {
System.out.println(" 小米手机打电话 ");
}
}
//手机抽象类
public abstract class Phone {
//组合品牌
private Brand brand;//品牌作为属性组合到手机抽象类中。
//即创建手机对象时,需传入手机品牌对象
//构造器
public Phone(Brand brand) {
super();
this.brand = brand;
}
protected void open() {
this.brand.open();
}
protected void close() {
brand.close();
}
protected void call() {
brand.call();
}
}
//手机抽象类子类:折叠手机,直立手机
//折叠式手机类,继承 抽象类 Phone
public class FoldedPhone extends Phone {
//构造器
public FoldedPhone(Brand brand) {
super(brand);
}
public void open() {
super.open();
System.out.println(" 折叠样式手机 ");
}
public void close() {
super.close();
System.out.println(" 折叠样式手机 ");
}
public void call() {
super.call();
System.out.println(" 折叠样式手机 ");
}
}
//直立手机
public class UpRightPhone extends Phone {
//构造器
public UpRightPhone(Brand brand) {
super(brand);
}
public void open() {
super.open();
System.out.println(" 直立样式手机 ");
}
public void close() {
super.close();
System.out.println(" 直立样式手机 ");
}
public void call() {
super.call();
System.out.println(" 直立样式手机 ");
}
}
//测试代码:
public static void main(String[] args) {
//获取折叠式手机 (样式 + 品牌 )
Phone phone1 = new FoldedPhone(new XiaoMi());
phone1.open();
phone1.call();
phone1.close();
System.out.println("=======================");
Phone phone2 = new FoldedPhone(new Vivo());
phone2.open();
phone2.call();
phone2.close();
System.out.println("==============");
UpRightPhone phone3 = new UpRightPhone(new XiaoMi());
phone3.open();
phone3.call();
phone3.close();
System.out.println("==============");
UpRightPhone phone4 = new UpRightPhone(new Vivo());
phone4.open();
phone4.call();
phone4.close();
}
比如这里的银行转账系统:可以把转账抽象成一个抽象类,里面聚合一个用户类型,网上转账,柜台转账,AMT转账是其子类。
写一个用户类型接口,有一个转账的方法,使普通用户,银卡用户,金卡用户实现此接口并实现转账方法即可。
三、装饰者模式
1、装饰者模式定义:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则。
这里有一个实例:星巴克咖啡订单:2份巧克力+一份牛奶的LongBlack
解决方案:
代码:
/**饮品抽象类
* @author admin
*/
public abstract class Drink {
private String dec;//描述
private float price;//价格
//计算费用的抽象方法,需要每一个子类去实现
public abstract float cost();//费用
public String getDec() {
return dec;
}
public void setDec(String dec) {
this.dec = dec;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
}
//将咖啡共有的特点再封装一个类
/**具体的某一类咖啡
* @author admin
*无因咖啡
*/
public class DeCaf extends Coffee {
public DeCaf() {
setDec("无因咖啡~~~");//设置自己的描述
setPrice(5.0f);//设置自己的价格
}
}
/**具体的某一类咖啡
* @author admin
*美式咖啡
*/
public class LongBlack extends Coffee {
public LongBlack() {
setDec("美式咖啡~~~");
setPrice(10.0f);
}
}
//装饰类
public class Decorator extends Drink{
//将被装饰者聚合类中
private Drink drink;
public Decorator(Drink drink) {
this.drink = drink;
}
@Override
public float cost() {
//super.getPrice():装饰着本身的价格 drink.cost():饮品的价格
return super.getPrice()+drink.cost();
}
public String getDec() {
if(drink!=null) {
//装饰着描述
return super.getDec()+": "+super.getPrice()+"\t"+drink.getDec();
}else {
return super.getDec()+": "+super.getPrice();
}
}
}
//豆浆装饰类
public class Soy extends Decorator{
public Soy(Drink drink) {
super(drink);
setDec("豆浆");
setPrice(1.5f);
}
}
//牛奶装饰类
public class Milk extends Decorator{
public Milk(Drink drink) {
super(drink);
setDec("牛奶 ");
setPrice(2.0f);
}
}
//巧克力装饰类
public class Chocolate extends Decorator {
public Chocolate(Drink drink) {
super(drink);
setDec("巧克力");
setPrice(2.0f);
}
}
//测试类
/**装饰者模式
* @author admin
*/
public class CoffeeStore {
public static void main(String[] args) {
//父类创建子类对象
Drink order = new DeCaf();
System.out.println("单品描述:" + order.getDec() + "\t单品价格:" + order.cost());
System.out.println();
//给咖啡中添加一份牛奶
order = new Milk(order);
//给咖啡中添加一份豆浆
order =new Soy(order);
System.out.println("order 加入一份牛奶+豆浆 费用 :" + order.cost());
System.out.println("order 加入一份牛奶 +豆浆描述=" + order.getDec());
System.out.println();
//加一份巧克力
order=new Chocolate(order);
System.out.println("order 加入一份牛奶+豆浆+巧克力 费用 :" + order.cost());
System.out.println("order 加入一份牛奶 +豆浆+巧克力描述=" + order.getDec());
}
}
四、组合模式
这里有个实例
解决方案就是把学校,院,系都看做是组织结构。他们之间没有继承关系,而是一个树形结构。
UML
//组织抽象类。学校,院,系都是组织抽象类的子类
public abstract class OrganizationComponent {
private String name;// 名字
private String des;// 描述
/**添加
* @param organizationComponent
*/
protected void add(OrganizationComponent organizationComponent) {
throw new UnsupportedOperationException();
}
/**移除:没有写成抽象方法的原因是,最小的节点不需要再继承添加/移除方法
* @param organizationComponent
*/
protected void remove(OrganizationComponent organizationComponent) {
throw new UnsupportedOperationException();
}
/**
* 输出打印
*/
protected abstract void print();
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;
}
}
/**大学
* @author admin
*
*/
public class University extends OrganizationComponent{
//添加一个集合,为下面添加学院使用
List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();
public University(String name, String des) {
super(name, des);
}
/**
*重写add方法
*/
@Override
protected void add(OrganizationComponent organizationComponent) {
organizationComponents.add(organizationComponent);
}
/**
*重写删除方法
*/
@Override
protected void remove(OrganizationComponent organizationComponent) {
organizationComponents.remove(organizationComponent);
}
@Override
public void setName(String name) {
super.setName(name);
}
@Override
public void setDes(String des) {
super.setDes(des);
}
@Override
protected void print() {
System.out.println("---------当前组织名称:"+getName()+"---------------");
for(OrganizationComponent oc:organizationComponents) {
oc.print();
}
}
}
/**学院
* @author admin
*
*/
public class College extends OrganizationComponent {
// 添加一个集合,为下面添加专业使用
List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();
public College(String name, String des) {
super(name, des);
}
/**
* 重写add方法
*/
@Override
protected void add(OrganizationComponent organizationComponent) {
organizationComponents.add(organizationComponent);
}
/**
* 重写删除方法
*/
@Override
protected void remove(OrganizationComponent organizationComponent) {
organizationComponents.remove(organizationComponent);
}
@Override
public void setName(String name) {
super.setName(name);
}
@Override
public void setDes(String des) {
super.setDes(des);
}
@Override
protected void print() {
System.out.println("---------当前组织名称:" + getName() + "---------------");
for (OrganizationComponent oc : organizationComponents) {
oc.print();
}
}
}
/**具体的 某一个专业
* @author admin
*
*/
public class Department extends OrganizationComponent{
public Department(String name, String des) {
super(name, des);
}
@Override
public void setName(String name) {
// TODO Auto-generated method stub
super.setName(name);
}
@Override
public void setDes(String des) {
// TODO Auto-generated method stub
super.setDes(des);
}
@Override
protected void print() {
System.out.println(getName());
}
}
/**
* 组合模式
* @author admin
*
*/
public class ClientTest {
public static void main(String[] args) {
//大学
OrganizationComponent university = new University("清华大学", "双一流");
//院
OrganizationComponent college = new College("计算机学院", "很有前途的学院");
//系
OrganizationComponent d1 = new Department("计算机科学与技术", "网管~~~");
OrganizationComponent d2 = new Department("网络专业", "不太好学");
// 将专业添加到学院中
college.add(d1);
college.add(d2);
// 将学院添加到学校中
university.add(college);
university.print();
}
}
五、外观模式
外观模式的基本介绍:
1)外观模式也叫'过程模式'。外观模式为子系统中的一组接口提供一个一致的界面。此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
2)外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用。而无需关心这个子系统的内部细节。
案例需求:
代码:
//一个个的设备类
public class DVDPlayer {
//使用单例模式, 使用饿汉式
private static DVDPlayer instance = new DVDPlayer();
public static DVDPlayer getInstanc() {
return instance;
}
public void on() {
System.out.println(" dvd on ");
}
public void off() {
System.out.println(" dvd off ");
}
public void play() {
System.out.println(" dvd is playing ");
}
public void pause() {
System.out.println(" dvd pause ..");
}
}
public class Popcorn {
private static Popcorn instance = new Popcorn();
public static Popcorn getInstance() {
return instance;
}
public void on() {
System.out.println(" popcorn on ");
}
public void off() {
System.out.println(" popcorn ff ");
}
public void pop() {
System.out.println(" popcorn is poping ");
}
}
。。。。。。
//外观类
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();
}
//设置统一的对外暴露方法
//此方法代理调用各个设备的功能方法
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();
}
}
//客户端调用
/**外观模式
* @author admin
*/
public class Client {
public static void main(String[] args) {
HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade();
homeTheaterFacade.ready();
homeTheaterFacade.play();
homeTheaterFacade.end();
}
}
六、享元模式
案例分析:当遇到这种项目中大部分功能呢需求一样,只有少数部分不一样的时候,传统思想肯定是将此项目再复制一份,针对不同的客户进行定制修改
享元模式原理:
UML:
代码:
//网站抽象类:里面包含的就是基本的公共方法
public abstract class WebSite {
public abstract void use(User user);//抽象方法
}
子类
//具体网站
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());
}
}
// 网站工厂类,根据需要返回压一个网站
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 User {
private String name;
public User(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//客户端代码
/**享元模式
* @author admin
*
*/
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("king"));
System.out.println("网站的分类共=" + factory.getWebSiteCount());
}
}
//执行结果:其实根据类型只有两种网站。有就直接调用不用去创建,没有就去新创建
网站的发布形式为:新闻 在使用中 .. 使用者是tom
网站的发布形式为:博客 在使用中 .. 使用者是jack
网站的发布形式为:博客 在使用中 .. 使用者是smith
网站的发布形式为:博客 在使用中 .. 使用者是king
网站的分类共=2
七、代理模式
静态代理:
代码:
//接口
public interface ITeacherDao {
void teach(); // 授课的方法
}
//目标对象
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
// TODO Auto-generated method stub
System.out.println(" 老师授课中 。。。。。");
}
}
//代理对象,静态代理
public class TeacherDaoProxy implements ITeacherDao{
private ITeacherDao target; // 目标对象,通过接口来聚合
//构造器
public TeacherDaoProxy(ITeacherDao target) {
this.target = target;
}
@Override
public void teach() {
System.out.println("开始代理 完成某些操作。。。。。 ");//方法
target.teach();
System.out.println("提交。。。。。");//方法
}
}
//客户端代码
public class Client {
public static void main(String[] args) {
//创建目标对象(被代理对象)
TeacherDao teacherDao = new TeacherDao();
//创建代理对象, 同时将被代理对象传递给代理对象
TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
//通过代理对象,调用到被代理对象的方法
//即:执行的是代理对象的方法,代理对象再去调用目标对象的方法
teacherDaoProxy.teach();
}
}
动态代理:
UML
代码:
//接口
public interface ITeacherDao {
void teach(); // 授课的方法
void sayHello(String str);
}
/**要被代理的对象
* @author admin
*
*/
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
// TODO Auto-generated method stub
System.out.println(" 老师授课中 。。。。。");
}
@Override
public void sayHello(String str) {
System.out.println("你好:"+str);
}
}
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
};
//给目标对象 生成一个代理对象
public Object getProxyInstance() {
//说明
/*
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
//1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
//2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
//3. InvocationHandler h : 事件处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
*/
//使用反射机制获取返回代理对象实例
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理开始~~");
//反射机制调用目标对象的方法
Object returnVal = method.invoke(target, args);
System.out.println("JDK代理提交");
return returnVal;
}
});
}
}
/**静态代理
* @author admin
*
*/
public class ClientTest {
public static void main(String[] args) {
// 创建目标对象
ITeacherDao target = new TeacherDao();
// 给目标对象,创建代理对象, 可以转成 ITeacherDao
ITeacherDao proxyInstance = (ITeacherDao) new ProxyFactory(target).getProxyInstance();
// proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
System.out.println("proxyInstance=" + proxyInstance.getClass());
// 通过代理对象,调用目标对象的方法
// proxyInstance.teach();
// 通过代理对象,调用目标对象的方法
proxyInstance.sayHello(" tom ");
}
}
以上是关于设计模式之结构型模式的主要内容,如果未能解决你的问题,请参考以下文章