设计模式之桥接模式

对象的继承关系是在编译时就定义好了,所以无法再运行时改变从父类继承的实现。

子类的实现与它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。

当你需要复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或其他更适合的类替换。这样的依赖关系限制了灵活性并最终限制了复用性。

合成/聚合复用原则

合成/聚合复用原则(CARP),尽量使用合成/聚成,尽量不要使用类继承

聚合表示一种弱的'拥有'关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分;

合成则是一种强的'拥有'关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样

优先使用对象的合成/聚合将有助于保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物。

桥接模式

桥接模式(Bridge),将抽象部分与它的实现部分分离,试它们都可以独立地变化

抽象与它的实现分离,这并不是说,让抽象类与其派生类分离,因为这没有任何意义。

实现指的是抽象类和它的派生类用来实现自己的对象

桥接模式基本代码

桥架模式(Bridge)结构图

csharp 复制代码
 class Program
    {
        static void Main(string[] args)
        {
            Abstraction ab = new Abstraction();
            ab.SetImplementor(new ConcreteImplementorA());
            ab.Operation();
            ab.SetImplementor(new ConcreteImplementorB());
            ab.Operation();
            Console.ReadLine();
        }
    }
    abstract class Implementor//实现者
    {
        public abstract void Operation();
    }
    class ConcreteImplementorA : Implementor//实现者1
    {
        public override void Operation()
        {
            Console.WriteLine("具体实现A的方法执行");
        }
    }
    class ConcreteImplementorB : Implementor//实现者2
    {
        public override void Operation()
        {
            Console.WriteLine("具体实现B的方法执行");
        }
    }
    class Abstraction//抽象
    {
        protected Implementor implementor;
        public void SetImplementor(Implementor implementor)
        {
            this.implementor = implementor;
        }
        public virtual void Operation()
        {
            implementor.Operation();
        }
    }
    class RefinedAbstraction : Abstraction
    {
        public override void Operation()
        {
            implementor.Operation();
        }
    }

实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让它们独立变化,减少它们之间的耦合

举例

桥接模式在游戏中也是十分常见的,比如角色与武器的配合实现

使用桥接模式实现"角色类群组"和"武器类群组"

ICharacter:角色的抽象接口拥有一个IWeapon对象引用,并且在接口中声明了一个武器攻击目标WeaponAttackTarget()方法让子类可以调用,同时要求继承的子类必须在Attack()中重新实现攻击目标的功能

IPlayer、IEnemy:敌人与玩家角色,实现攻击目标Attack()时,只需要调用父类的WeaponAttackTarget()方法,就可以使用当前装备的武器攻击对手

IWeapon:武器接口,定义游戏中对于武器的操作和使用方法

WeaponGun、WeaponRocket、WeaponRifle:游戏中可以使用的3种武器类型的实现。

csharp 复制代码
 class Program
    {
        static void Main(string[] args)
        {
            IEnemy enemy = new IEnemy();
            IPlayer player = new IPlayer();

           WeaponGun weapon = new WeaponGun();
           WeaponRocket weapon1 = new WeaponRocket();

            enemy.SetWeapon(weapon);
            enemy.GetWeapon().Fire();

            player.SetWeapon(weapon1);
            player.GetWeapon().Fire();

            Console.ReadLine();


        }
    }

    public abstract class IWeapon//武器类
    {
        public string name = "武器";
        //属性
        protected int m_AtkPlusValue = 0;//额外增加的攻击力

        protected int m_Atk = 0;//攻击力

        protected float m_Range = 0.0f;//攻击距离

        protected ICharacter m_WeaponOwner = null;//武器的拥有者


        public abstract void Fire(); //攻击目标
        
       
    }

    public class WeaponGun : IWeapon//手枪
    {
     public   string name = "手枪";
        public override void Fire()
        {
            Console.WriteLine("火枪开火");
        }
    }
    public class WeaponRifle : IWeapon//步枪
    {
      public  string name = "步枪";
        public override void Fire()
        {
            Console.WriteLine("步枪开火");
        }
    }
    public class WeaponRocket : IWeapon//火箭炮
    {
      public  string name = "火箭炮";
        public override void Fire()
        {
            Console.WriteLine("火箭炮开火");
        }
    }



    public abstract class ICharacter
    {
        private IWeapon m_Weapon = null;//使用武器

        //设置使用的武器
        public void SetWeapon(IWeapon Weapon)
        {
           
            if (m_Weapon == null)
            {
                m_Weapon = Weapon;
                Console.WriteLine("设置装备武器{0}",m_Weapon.name);
            
            }
        }

        //获取武器
        public IWeapon GetWeapon()
        {
            return m_Weapon;
        }

       
        public abstract void Attack(ICharacter Target);



        public abstract void UnderAttack(ICharacter Attacker);



    }


    public class IPlayer : ICharacter//玩家
    {
        //攻击目标
        public override void Attack(ICharacter Target)
        {

        }
        
        //被其他角色攻击
        public override void UnderAttack(ICharacter Attacker)
        {

        }
    }

    public class IEnemy : ICharacter//敌人
    {
        public override void Attack(ICharacter Target)
        {
           
        }

        public override void UnderAttack(ICharacter Attacker)
        {
           
        }
    }
相关推荐
小海编码日记11 分钟前
Java八股-JVM & GC
java
全职计算机毕业设计16 分钟前
基于Java Web的校园失物招领平台设计与实现
java·开发语言·前端
东阳马生架构22 分钟前
商品中心—1.B端建品和C端缓存的技术文档
java
Chan1625 分钟前
【 SpringCloud | 微服务 MQ基础 】
java·spring·spring cloud·微服务·云原生·rabbitmq
LucianaiB28 分钟前
如何做好一份优秀的技术文档:专业指南与最佳实践
android·java·数据库
面朝大海,春不暖,花不开1 小时前
自定义Spring Boot Starter的全面指南
java·spring boot·后端
得过且过的勇者y1 小时前
Java安全点safepoint
java
夜晚回家1 小时前
「Java基本语法」代码格式与注释规范
java·开发语言
斯普信云原生组2 小时前
Docker构建自定义的镜像
java·spring cloud·docker
wangjinjin1802 小时前
使用 IntelliJ IDEA 安装通义灵码(TONGYI Lingma)插件,进行后端 Java Spring Boot 项目的用户用例生成及常见问题处理
java·spring boot·intellij-idea