设计模式-结构性设计模式

外观模式

  • 定义
    又叫门面模式,提供一个统一的接口,用来访问子系统的一群接口
    外观模式定义了一个高层接口,让子系统更容易使用

  • 适用场景
    子系统越来越复杂,增加外观模式提供简单调用接口
    构建多层系统结构,利用外观对象作为每层的入口,简化层间调用

  • 优点
    简化了调用过程,无需了解深入子系统,防止带来风险
    减少系统依赖、松散耦合
    更好的划分访问层次
    符合迪米特原则,即最少知道原则
    符合合成复用原则

  • 缺点
    增加子系统、扩展子系统行为容易引入风险
    不符合开闭原则

积分兑换服务依赖3个子系统:分别是积分-库存校验服务、积分扣除服务、物流对接服务。主系统只提供一个简单调用的接口,应用层Test不关心子系统的运作
image

适配器模式

  • 定义
    将一个类的接口转换成客户期望的另一个接口
    使原本接口不兼容的类可以一起工作

  • 适用场景
    已经存在的类,它的方法和需求不匹配时(方法结果相同或相似)
    不是软件设计阶段考虑的设计模式,而是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案

  • 优点
    能提高类的透明性和复用,现有的类复用但不需要改变
    目标类和适配器类解耦,提高程序扩展性
    符合开闭原则

  • 缺点
    适配器编写过程需要全面考虑,可能会增加系统的复杂性
    增加系统代码可读的难度

  • 类适配器

/**目标接口
 * @author MrPeng
 * @date 2019/2/14
 */
public interface Target {
    void request();
}
------------------------
/**目标实现类
 * @author MrPeng
 * @date 2019/2/14
 */
public class ImpTarget implements Target {
    @Override
    public void request() {
        System.out.println("ImpTarget目标实现方法");
    }
}
----------------------------
/**被适配者
 * @author MrPeng
 * @date 2019/2/14
 */
public class Adaptee {
    public void adapteeRequest(){
        System.out.println("被适配者的方法");
    }
}
-----------------------------------------

/**类适配器--通过继承重写被适配者的方法
 * @author MrPeng
 * @date 2019/2/14
 */
public class Adapter extends Adaptee implements Target {
    @Override
    public void request() {
        //重写的逻辑代码...
        super.adapteeRequest();
        //重写的逻辑代码...
    }
}
-------------------------------------------
/**适配器模式测试
 * @author MrPeng
 * @date 2019/2/14
 */
public class Test {
    public static void main(String[] args) {
        Target target = new ImpTarget();
        target.request();

        Target adapterTarget = new Adapter();
        adapterTarget.request();
    }
}
  • 对象适配器
/**对象适配器--不使用继承,而是通过组合
 * @author MrPeng
 * @date 2019/2/14
 */
public class Adapter implements Target {
    private Adaptee adaptee = new Adaptee();
    @Override
    public void request() {
        //重写的逻辑代码...
        adaptee.adapteeRequest();
        //重写的逻辑代码...
    }
}

桥接模式

  • 定义
    将抽象部分与它的具体实现部分分离,使它们都可以独立变化
    通过组合的方式建立两个类之间的联系,而不是继承
  • 适用场景
    抽象和具体实现之间增加更多灵活性
    一个类存在两个或多个独立变化的维度,且这些维度都需要独立进行扩展
    不希望使用继承,或因为多层继承导致系统类的个数剧增
  • 优点
    分离抽象部分和其具体实现部分
    提高了系统的可扩展性
    符合开闭原则
    符合合成复用原则
  • 缺点
    增加了系统的理解和设计难度
    需要正确地识别出系统中两个独立变化的维度
/**帐号接口
 * @author MrPeng
 * @date 2019/2/16
 */
public interface Account {
    Account openAccount();
    void showAccountType();
}
-----------------------------
/**定期帐号--实现帐号接口
 * @author MrPeng
 * @date 2019/2/16
 */
public class DepositAccount implements Account {
    @Override
    public Account openAccount() {
        System.out.println("打开定期账号");
        return new DepositAccount();
    }

    @Override
    public void showAccountType() {
        System.out.println("这是一个定期账号");
    }
}
-------------------------------------
/**银行抽象
 * @author MrPeng
 * @date 2019/2/16
 */
public abstract class Bank {
    protected Account account;
    public Bank(Account account){
        this.account = account;
    }
    abstract Account openAccount();
}
---------------------------------
/**工商银行
 * @author MrPeng
 * @date 2019/2/16
 */
public class ICBCBank extends Bank {
    public ICBCBank(Account account) {
        super(account);
    }

    @Override
    Account openAccount() {
        System.out.println("打开中国工商银行账号");
        //关键部分
        account.openAccount();
        return account;
    }
}
---------------------
public static void main(String[] args) {
    Bank icbcBank = new ICBCBank(new DepositAccount());
    Account icbcAccount = icbcBank.openAccount();
    icbcAccount.showAccountType();
}

组合模式

  • 定义
    将对象组合成树形结构以表示“部分-整体”的层次结构
    组合模式使客户端对单个对象和组合对象保持一致的方式处理
  • 适用场景
    希望客户端可以忽略组合对象与单个对象的差异时
    处理一个树形结构时
  • 优点
    清楚地定义分层次和复杂对象,表示对象的全部或部分层次
    让客户端忽略了层次的差异,方便对整个层次结构进行控制
    简化客户端代码
    符合开闭原则
  • 缺点
    限制类型时会较为复杂
    使设计变得更加抽象

测试场景:无限极分类

/**目录组件
 * @author MrPeng
 * @date 2019/2/14
 */
public abstract class CatalogComponent {
    public void add(CatalogComponent catalogComponent){
        throw new UnsupportedOperationException("不支持添加操作");
    }

    public void remove(CatalogComponent catalogComponent){
        throw new UnsupportedOperationException("不支持删除操作");
    }

    public String getName(CatalogComponent catalogComponent){
        throw new UnsupportedOperationException("不支持获取名称操作");
    }

    public double getPrice(CatalogComponent catalogComponent){
        throw new UnsupportedOperationException("不支持获取价格操作");
    }

    public void print(){
        throw new UnsupportedOperationException("不支持打印操作");
    }
}
---------------------------------------------
/**课程
 * @author MrPeng
 * @date 2019/2/14
 */
public class Course extends CatalogComponent {
    private String name;
    private double price;

    public Course(String name, double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String getName(CatalogComponent catalogComponent) {
        return this.name;
    }

    @Override
    public double getPrice(CatalogComponent catalogComponent) {
        return this.price;
    }

    @Override
    public void print() {
        System.out.println("Course Name:"+name+" Price:"+price);
    }
}
-------------------------------------
**课程目录
 * @author MrPeng
 * @date 2019/2/14
 */
public class CourseCatalog extends CatalogComponent {
    private List<CatalogComponent> items = new ArrayList<CatalogComponent>();
    private String name;//目录名称
    private Integer level;//目录等级


    public CourseCatalog(String name,Integer level) {
        this.name = name;
        this.level = level;
    }

    @Override
    public void add(CatalogComponent catalogComponent) {
        items.add(catalogComponent);
    }

    @Override
    public String getName(CatalogComponent catalogComponent) {
        return this.name;
    }

    @Override
    public void remove(CatalogComponent catalogComponent) {
        items.remove(catalogComponent);
    }

    @Override
    public void print() {
        System.out.println(this.name);
        for(CatalogComponent catalogComponent : items){
            if(this.level != null){
                for(int  i = 0; i < this.level; i++){
                    System.out.print("  ");
                }
            }
            catalogComponent.print();
        }
    }
}
-------------------------------------
public class Test {
    public static void main(String[] args) {
        CatalogComponent javaCourseCatalog = new CourseCatalog("Java课程目录",2);
        CatalogComponent course1 = new Course("Java零基础入门",55);
        CatalogComponent course2 = new Course("JavaWeb入门",66);
        javaCourseCatalog.add(course1);
        javaCourseCatalog.add(course2);

        CatalogComponent phpCourseCatalog = new CourseCatalog("PHP课程目录",2);
        CatalogComponent course3 = new Course("PHP零基础入门",55);
        CatalogComponent course4 = new Course("PHP源码解析",66);
        phpCourseCatalog.add(course3);
        phpCourseCatalog.add(course4);

        CatalogComponent mainCatalog = new CourseCatalog("主目录",1);
        mainCatalog.add(javaCourseCatalog);
        mainCatalog.add(phpCourseCatalog);

        mainCatalog.print();
    }
}

image

装饰器模式

  • 定义
    在不改变原有对象的基础上,将功能附加到对象上
    提供了比继承更有弹性的替代方案(扩展原有对象功能)
  • 适用场景
    扩展一个类的功能或给一个类添加附加职责
    动态的给一个对象添加功能、这些功能可以动态的撤销
  • 优点
    继承的有利补充、比继承灵活、不改变原有对象的情况下给一个对象扩展功能
    通过使用不同的装饰类以及这些装饰类的排列组合,可以实现不同效果
    符合开闭原则
  • 缺点
    会出现更多的代码、更多的类、增加程序复杂性
    动态装饰时,多层装饰时会更复杂

image

//创建一个普通煎饼
BaseCake baseCake = new Cake();
baseCake = new EggDecorator(baseCake);
baseCake = new EggDecorator(baseCake);
baseCake = new HotDogDecorator(baseCake);
System.out.println(baseCake.getDesc()+" 销售价格:"+baseCake.getPrice());

image

享元模式

  • 定义
    提供了减少对象数量从而改善应用所需的对象结构方式
    运用共享技术有效的支持大量细粒度的对象
  • 适用场景
    常常应用于系统底层的开发,以便解决系统的性能问题
    系统有大量对象,需要缓冲池的场景
  • 优点
    减少对象的创建,降低内存中对象的数量,降低系统的内存,提高效率
    减少内存之外的其他资源占用(例如new对象的时间开销)
  • 缺点
    关注内/外状态、线程安全问题
    使系统、程序的逻辑复杂化
  • 扩展
    内部状态
    外部状态

image

/**员工接口
 * @author MrPeng
 * @date 2019/2/14
 */
public interface Employee {
    void report();
}
------------------------
/**部门经理
 * @author MrPeng
 * @date 2019/2/14
 */
public class Manager implements Employee {
    @Override
    public void report() {
        System.out.println(reportContent);
    }

    /**
     * 内部状态--外部无法改变
     */
    private String title = "部门经理";
    /**
     * 外部状态--传入部门不同导致部门经理也不同
     */
    private String department;
    private String reportContent;

    public void setReportContent(String reportContent) {
        this.reportContent = reportContent;
    }

    public Manager(String department) {
        this.department = department;
    }
}
--------------------------------------
/**工厂类
 * @author MrPeng
 * @date 2019/2/14
 */
public class EmployeeFactory {
    private static final Map<String,Employee> EMPLOYEE_MAP = new HashMap<>();

    public static Employee getManager(String department){
        Manager manager = (Manager) EMPLOYEE_MAP.get(department);

        if(manager == null){
            manager = new Manager(department);
            System.out.print("创建部门经理:"+department);
            String reportContent = department+"部门汇报:此次报告的主要内容是......";
            manager.setReportContent(reportContent);
            System.out.println(" 创建报告:"+reportContent);
            EMPLOYEE_MAP.put(department,manager);

        }
        return manager;
    }
}
------------------------------
public class Test {
    private static final String departments[] = {"销售部","研发部","人事部"};

    public static void main(String[] args) {
        for(int i=0; i<10; i++){
            String department = departments[(int)(Math.random() * departments.length)];
            Manager manager = (Manager) EmployeeFactory.getManager(department);
            manager.report();

        }
    }
}

代理模式

  • 定义
    为其他对象提供一种代理以控制对这个对象的访问
    代理对象在客户端和目标对象之间起中介作用
  • 适用场景
    保护目标对象
    增强目标对象
  • 优点
    职责清晰
    代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。
    降低系统耦合,扩展性好
  • 缺点
    代理模式会造成系统设计中类数目增加
    在客户端和目标对象中增加代理对象,会降低处理速度
    增加系统复杂度
  • 扩展
    静态代理
    动态代理--JDK--java.lang.reflect.InvocationHandler接口
    CGLib代理--CGLIB(Code Generation Library)是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。
/**被追求者类
 * @author MrPeng
 * @date 2019/2/18
 */
public class Girl {
    private String name;
    //get/set忽略
}
------------------------------------
/**送礼物接口
 * @author MrPeng
 * @date 2019/2/18
 */
public interface GiveGift {
    void giveDolls();
}
-------------------------------------
/**追求者类
 * @author MrPeng
 * @date 2019/2/18
 */
public class Pursuit implements GiveGift{
    private Girl mm;

    public Pursuit(Girl girl) {
        this.mm = girl;
    }

    @Override
    public void giveDolls() {
        System.out.println(mm.getName()+" 送娃娃");
    }
}
----------------------------------------------------
/**代理类
 * @author MrPeng
 * @date 2019/2/18
 */
public class Proxy implements GiveGift {

    private Pursuit gg;

    public Proxy(Girl girl){
        gg = new Pursuit(girl);
    }

    @Override
    public void giveDolls() {
        //可以通过代理增强类的功能--而不需要改变原来的逻辑
        System.out.print("通过代理向--");
        gg.giveDolls();
        System.out.println("送完娃娃看电影...");
    }
}
--------------------------------------------
public static void main(String[] args) {
    Girl girl = new Girl();
    girl.setName("小红");

    Proxy proxy = new Proxy(girl);
    proxy.giveDolls();
}
posted @ 2023-05-26 21:20  Ranger-dev  阅读(18)  评论(0编辑  收藏  举报