java----设计模式--结构型模式(GOF23)
核心作用:是从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题。
适配器设计模式:
将一个类的接口转换成客户希望的另一个的接口
适配器使原本由于接口不兼容而不能工作的那些类可以一起工作
适配器比较经典的案例
java.io.InputStreamReader(InputStream) java.io.OutputStreamWriter(OutputStream)

感觉是配置有一点类似静态代理,但是适配器可能需要继承或者实现某一个类或者接口
采用组合的方式(推荐使用)
public class Demo {
public static void main(String[] args){
work(new PowerAachieve());
//work(new PowerBachieve()); //接口A接受不了接口B
Adapter adapter = new Adapter(new PowerBachieve()); //利用适配器接入接口A。接口B接入到适配器上即可
work(adapter);
}
public static void work(PowerA power){ //接口A(可以接受是适配器,不能接受接口B)
power.insert();
}
}
interface PowerA{
void insert();
}
class PowerAachieve implements PowerA{
public void insert(){
System.out.println("接口A开始工作");
}
}
//适配器
class Adapter implements PowerA{ //适配器必须继承接口B,将接口B接入到适配器上
private PowerB power;
public Adapter(PowerB power){
this.power = power;
}
public void insert(){
this.power.connect();
}
}
interface PowerB{
void connect();
}
class PowerBachieve implements PowerB{
public void connect(){
System.out.println("接口B开始工作");
}
}
采用继承的方式(适配器继承需要调用的类,不推荐使用,作为了解)
public class Demo {
public static void main(String[] args){
Adapter adapter = new Adapter(); //利用适配器接入接口A。接口B接入到适配器上即可
work(adapter);
}
public static void work(PowerA power){ //接口A(可以接受是适配器,不能接受接口B)
power.insert();
}
}
interface PowerA{
void insert();
}
class PowerAachieve implements PowerA{
public void insert(){
System.out.println("接口A开始工作");
}
}
class Adapter extends PowerBachieve implements PowerA{ //适配器必须继承接口B,将接口B接入到适配器上
public void insert(){
this.connect();
}
}
interface PowerB{
void connect();
}
class PowerBachieve implements PowerB{
public void connect(){
System.out.println("接口B开始工作");
}
}
适配器用途二
public class Demo {
public static void main(String[] args){
work(new Dog());
}
public static void work(Animal animal){ //接口Animal(可以接受是适配器)
animal.run();
}
}
interface Animal{
void run();
void sing();
void swim();
void fly();
}
//class Dog implements Animal{
// public void run(){};
// public void sing(){};
// public void swim(){
// System.out.println("如果只要实现swim方法,但是需要将所有继承的方法都是实现(可以不写其代码)");
// };
// public void fly(){};
//}
//利用适配器实现所有的接口,其他的类直接继承适配器.这样的好处是不用每一个类都要实现所有的方法.
abstract class Adapter implements Animal{
public void run(){};
public void sing(){};
public void swim(){};
public void fly(){};
}
class Dog extends Adapter{
public void run(){
System.out.println("我可以跑");
}
}
静态代理模式:
注意代理的核心思想就是做AOP
在运行前就已经将代理写好了
为其他对象提供一种代理以控制对这个对象的访问
被代理的代码有完整的业务实现,可以单独运行。而通过代理可以添加一些其他的需求。然后通过代理来控制被代理的业务实现。
静态代理类对象是由自己实现的:缺陷,如果被代理的对象需要增加方法,那么代理类也需要额外添加对应的方法,而且会造成代码冗余。
public class Demo {
public static void main(String[] args){
Proxy proxy = new Proxy(new Phone());
proxy.work();
}
}
interface Action{
void work();
}
class Phone implements Action{ //被代理
public void work(){
System.out.println("手机开始工作");
}
}
//代理类必须实现被代理类的所有的方法,所以需要实现被代理类的所有的方法;
class Proxy implements Action{
private Action action;
public Proxy(){}
public Proxy(Action action){
this.action = action;
}
public void work(){
long starttime = System.currentTimeMillis();
this.action.work();
long endtime = System.currentTimeMillis();
System.out.println("一共耗时:"+(endtime - starttime)+"毫秒");
}
}
动态代理模式:
这样创建出来的代理类是什么样的?
大概是程序会自动生成一个代理类,这给代理类实现了所有的接口(我们传入的),代理类对象就会实现接口中的所有的方法,方法里面的逻辑都是去调用invoke()方法;
动态代理,就是根据对象在内存中加载的Class类创建运行时类对象,从而调用代理类方法和属性。
public class Demo {
public static void main(String[] args) {
CreateProxy createproxy = new CreateProxy();
Customer customer = new Customer();
//注意只能强转成接口类型 Subject
Subject subject = (Subject) createproxy.create(customer);
subject.shopping(); //会调用invoke方法
}
}
interface Subject {
void shopping();
}
class Customer implements Subject {
@Override
public void shopping() {
System.out.println("付款,购买物品");
}
}
//用于动态生成一个代理对象
class CreateProxy implements InvocationHandler {
//传入target的目的是因为invoke(target, args)方法需要传入一个target对象,这个对象就是被代理的对象
private Object target;
public Object create(Object target) {
this.target = target;
//newProxyInstance参数类加载器,接口数组,this,接口是动态加载的(可以调用多个接口)
//ClassLoader loader:类加载器
//Class<?>[] interfaces:接口数组,可以写成这样:new Class[]{Subject.class}
//InvocationHandler h: 实现InvocationHandler接口的类
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 {
System.out.println(method.getName()); //可以用它来判断特定的方法执行不同的功能;
System.out.println("正在挑选商品.....");
System.out.println("已挑选好商品.....,等待客户确认订单");
method.invoke(target, args);
System.out.println("订单完成");
return null;
}
}
静态代理和动态代理的对比
参考:https://www.cnblogs.com/baizhanshi/p/6611164.html 写的很详细
静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
优点:代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合)
缺点:1、代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
2、代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。
动态:在程序运行时运用反射机制动态创建而成。
优点:如果静态代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类,而动态代理,只需要一个代理类,在代理类中添加不同的代理方法(返回不同的代理对象)即可。
不需要实现委代理类的每一个实现方法,减少代码的冗余
桥接模式:

采用组合方式解决多继承的复杂模式
桥接模式核心要点:
-处理多层继承结构,处理多维度变化的场景,将各个维度设计成独立的继承结构,使各个维度可以独立的扩展在抽象层建立关联。
使用场景
--JDBC驱动程序
--AWT中的Peer架构
--银行日志管理:
·格式分类:操作日志、交易日志、异常日志
·距离分类:本地记录日志、异地记录日志
--人力资源系统中的奖金计算模块:
奖金分类:个人奖金、团体奖金、激励奖金。·
部门分类:人事部门、销售部门、研发部门。
--OA系统中的消息处理:
业务类型:普通消息、加急消息、特急消息
发送消息方式:系统内消息、手机短信、邮件
需求:有一个品牌电脑A和B,他们下面都要有2个销售的类型(笔记本和台式机),所以笔记本类和台式机类搜需要继承各自的品牌类
如果现在又要添加一个新的品牌,就又要添加2个销售的类型(这会造成代码冗余,笔记本类的代码都是一样的);
我们可以将品牌和笔记本/台式机类采用组合的方式,桥接起来
public interface Brand {
void sale();
}
class Lenovo implements Brand{
@Override
public void sale() {
System.out.println("销售联想电脑");
}
}
class Dell implements Brand{
@Override
public void sale() {
System.out.println("销售Dell电脑");
}
}
public class Computer {
private Brand brand;
public Computer(Brand brand) {
this.brand = brand;
}
public void sale(){
this.brand.sale();
}
}
class Desktop extends Computer{
public Desktop(Brand brand) {
super(brand);
}
@Override
public void sale() {
super.sale();
System.out.println("销售台式机");
}
}
class laptop extends Computer{
public laptop(Brand brand) {
super(brand);
}
@Override
public void sale() {
super.sale();
System.out.println("销售笔记本");
}
}
demo
public class Demo {
public static void main(String[] args) {
Desktop desktop = new Desktop(new Lenovo());
desktop.sale();
}
}
组合模式:
组合和组合设计模式不一样
组合在A类里边添加一个B类这个属性(可以通过构造方法传入B类对象),此时A类就可以调用B类的所有的方法了
使用场景
把部分和整体的关系用树形结构(类似二叉树)来表示,从而使客户端可以使用统一的方式处理部分对象和整体对象。
组合模式核心:
-抽象构件(Component)角色:定义了叶子和容器构件的共同点
-叶子(Leaf)构件角色:无子节点
-容器(Composite)构件角色:有容器特征,可以包含子节点
开发中的应用场景:
-操作系统的资源管理器-GUI中的容器层次图
-XML文件解析
-OA系统中,组织结构的处理
-Junit单元测试框架
底层设计就是典型的组合模式,TestCase(叶子)、TestUnite(容器)、Test接口(抽象)
抽象组件
public interface Component {
void operation();
}
//容器节点
interface Composite extends Component{
void add(Component c);
void remove(Component c);
Component getChild (int index);
}
//叶子节点
interface leaf extends Composite{
}
使用组合模式,模拟杀毒软件架构设计
public interface AbstractFile {
void killVirus();
}
//叶子节点
class ImageFile implements AbstractFile{
@Override
public void killVirus() {
System.out.println("ImageFile正在被查杀");
}
}
//叶子节点
class TextFile implements AbstractFile{
@Override
public void killVirus() {
System.out.println("TextFile正在被查杀");
}
}
//容器节点
class Folder implements AbstractFile{
private List<AbstractFile> list = new ArrayList<AbstractFile>(); //通过容器节点将各个节点关联起来
@Override
public void killVirus() {
System.out.println("Folder进行查杀");
list.forEach((AbstractFile abstractFile)->{abstractFile.killVirus();});
}
void add(AbstractFile c){
list.add(c);
};
void remove(AbstractFile c){
list.remove(c);
};
AbstractFile getChild (int index){
AbstractFile abstractFile = list.get(index);
return abstractFile;
};
}
demo
public class Demo {
public static void main(String[] args) {
Folder folder = new Folder();
folder.add(new TextFile());
folder.add(new ImageFile());
folder.add(new TextFile());
//操作容器
folder.killVirus();
//操作叶子
new TextFile().killVirus();
}
}
装饰者设计模式:
动态为对象添加新的功能(可以修改对象的属性,可以进行方法的扩展)
开发中使用的场景:
-IO中输入流和输出流的设计
-Swing包中图形界面构件功能
-Servlet API 中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper,HttpServletRequestWrapper类,增强了request对象的功能。
-Struts2中,request,response,session对象的处理
public class Test {
public static void main(String[] args){
Milk milk = new Milk();
Coffer coffer = new Coffer(milk);
Coke coke = new Coke(coffer);
System.out.println(coke.cost()+","+coke.desc());
}
}
interface Drink{
float cost();
String desc();
}
class Milk implements Drink{
@Override
public float cost() {
return 10f;
}
@Override
public String desc() {
return "牛奶";
}
}
//如果没有这个所有的修饰类都需要添加Drink属性,代码冗余
abstract class Decorator implements Drink{
private Drink drink;
public Decorator(Drink drink){
this.drink = drink;
}
@Override
public float cost() {
return this.drink.cost();
}
@Override
public String desc() {
return this.drink.desc();
}
}
class Coffer extends Decorator{
public Coffer(Drink drink) {
super(drink);
}
@Override
public float cost() {
return super.cost()+1.0f;
}
@Override
public String desc() {
return super.desc()+"加咖啡";
}
}
class Coke extends Decorator{
public Coke(Drink drink) {
super(drink);
}
@Override
public float cost() {
return super.cost()+1.0f;
}
@Override
public String desc() {
return super.desc()+"加可乐";
}
}
外观模式:
迪米特法则(最少知识原则)
一个软件实体应当尽可能少的与其他实体发生相互作用。
外观模式核心
为子系统提供统一的入口。封装子系统的复杂性,便于客户端调用。

class A{
void test(){
System.out.println("去工商局");
}
}
class B{
void test(){
System.out.println("去税务局");
}
}
public class Door {
//注册公司
void register(){
new A().test();
new B().test();
}
}
demo
public class Demo {
public static void main(String[] args) {
//new A().test();
//new B().test();
//只需要和这一个类打交道
new Door().register();
}
}
享元模式:
场景:
内存属于稀缺资源,不要随便浪费。如果有很多个完全相同或相似的对象,我们可以通过享元模式,节省内存,但是增加了运行时间;
核心:
享元模式以共享的方式高效地支持大量细粒度对象的重用。
享元对象能做到共享的关键是区分了内部状态和外部状态。
内部状态:可以共享,不会随环境变化而改变
外部状态:不可以共享,会随环境变化而改变
比如一个围棋中,所有的棋子大小形状颜色都是可以共享的,但是棋子的位置不能共享
享元模式实现
普通类:包含了所有的共享变量,有一个方法可以传入非共享变量(该变量不能被存储,所以方法结束变量清空,所以需要在方法中将非共享变量作用使用出来);
享元工厂:使用单例缓冲值,同一个key的对象只能有一个(如果全部对象都只有一个key,完全可以用单例来代替享元工厂)
开发过程中应用场景
享元模式由于其共享的特性,可以在任何“池"中操作,比如:线程池、数据库连接池。
String类的设计也是享元模式
//享元类
public interface ChessFlyWeight {
void setColor(String c);
String getColor();
void display(Coordinate coordinate);
}
class Coordinate{
public int x;
public int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
}
class ConcreteChess implements ChessFlyWeight{
public String color;
public ConcreteChess(String color) {
this.color = color;
}
@Override
public void setColor(String c) {
color =c;
}
@Override
public String getColor() {
return color;
}
@Override
public void display(Coordinate coordinate) {
System.out.println("棋子颜色:"+color);
System.out.println("棋子位置:x="+coordinate.x+",y="+coordinate.y);
}
}
//享元工厂类(核心使用了单例缓冲池)
class ChessFlyWeightFactory{
//享元池
private static Map<String,ChessFlyWeight> map= new HashMap<>();
public static ChessFlyWeight getChess(String color){
ChessFlyWeight chessFlyWeight = map.get(color);
if (chessFlyWeight==null){
chessFlyWeight = new ConcreteChess(color);
map.put(color,chessFlyWeight);
}
return chessFlyWeight;
}
}
class Demo{
public static void main(String[] args) {
ChessFlyWeight chess = ChessFlyWeightFactory.getChess("黑");
ChessFlyWeight chess1 = ChessFlyWeightFactory.getChess("黑");
System.out.println(chess==chess1);
//非共享的变量从外部传递
chess.display(new Coordinate(1,1));
chess1.display(new Coordinate(2,2));
}
}

浙公网安备 33010602011771号