zoukankan      html  css  js  c++  java
  • 设计原则:请重新审视“多重继承”,找机会拥抱一下“掺入(Mixin)”

    名称解释

    多重继承:我没有使用多重继承的经验,因此这里不多说,大学学的C++,可惜没有学好。

    Mixin:一个Mixin是一个方法和属性的集合,不同的语言提供的实现机制不一样。类型定义的时候可以声明他想包含的Mixin(可以是多个),这些Mixin包含的方法会成为类型的一部分。

    使用动机

    代码复用 AND 运行时不改变。

    Mixin是推论,MixinTarget是定理。如:C#的IEnumerable(MixinTarget)只包含一个方法,根据这个方法(定理)Enumerable(Mixin)扩展了N个方法(推论)。

    示例(ExtJs4.2)

     1 /// <reference path="../ext-all-debug-w-comments.js" />
     2  Ext.define('Enjoyable', {
     3      play: function () {
     4          console.log(this.getName() + '-play');
     5      }
     6  });
     7  
     8  Ext.define('Workable', {
     9      work: function () {
    10          console.log(this.getName() + '-work');
    11      }
    12  });
    13  
    14  Ext.define('User', {
    15      mixins: {
    16          'enjoyable': 'Enjoyable',
    17          'workable': 'Workable'
    18      },
    19      config: { name: 'unknow' },
    20  
    21      constructor: function () {
    22          var me = this;
    23  
    24          me.initConfig(arguments);
    25      },
    26  
    27      eat: function () {
    28          for (var i = 0; i < arguments.length; i++) {
    29              console.log(arguments[i]);
    30          }
    31      }
    32  });
    33  
    34  var user = Ext.create('User');
    35  
    36  user.setName('段光伟');
    37  
    38  user.play();
    39  user.work();

    示例(C#扩展方法)

     1 using System;
     2  using System.Collections.Generic;
     3  using System.Linq;
     4  using System.Text;
     5  using System.Threading.Tasks;
     6  
     7  namespace MixinDemo
     8  {
     9      public class User
    10      {
    11          public string Name { get; set; }
    12      }
    13  
    14      public static class Enjoyable
    15      {
    16          public static void Play(this User user)
    17          {
    18              Console.WriteLine(user.Name + "-play");
    19          }
    20      }
    21  
    22      public static class Workable
    23      {
    24          public static void Work(this User user)
    25          {
    26              Console.WriteLine(user.Name + "-work");
    27          }
    28      }
    29  }

    示例(C#动态代理)

      1 using System;
      2  using System.Collections.Generic;
      3  using System.Linq;
      4  using System.Text;
      5  using System.Threading.Tasks;
      6  
      7  using Castle.DynamicProxy;
      8  using Castle.DynamicProxy.Generators;
      9  
     10  namespace MixinStudy
     11  {
     12      class Program
     13      {
     14          static void Main(string[] args)
     15          {
     16              var proxy = Factory.Create<User>();
     17              proxy.Id = Guid.NewGuid();
     18              proxy.Name = "段光伟";
     19  
     20              (proxy as ITeacher).Teach();
     21              (proxy as IFather).Play();
     22          }
     23      }
     24  
     25      [Mixin(typeof(Teacher))]
     26      [Mixin(typeof(Father))]
     27      public class User
     28      {
     29          public virtual Guid Id { get; set; }
     30          public virtual string Name { get; set; }
     31      }
     32  
     33      public interface ITeacher
     34      {
     35          User User { get; set; }
     36  
     37          void Teach();
     38      }
     39  
     40      public class Teacher : ITeacher
     41      {
     42          [MixinTarget]
     43          public User User { get; set; }
     44  
     45          public void Teach()
     46          {
     47              Console.WriteLine("我教你读书吧:" + this.User.Name);
     48          }
     49      }
     50  
     51      public interface IFather
     52      {
     53          User User { get; set; }
     54  
     55          void Play();
     56      }
     57  
     58      public class Father : IFather
     59      {
     60          [MixinTarget]
     61          public User User { get; set; }
     62  
     63          public void Play()
     64          {
     65              Console.WriteLine("我陪你玩吧:" + this.User.Name);
     66          }
     67      }
     68  
     69      public static class Factory
     70      {
     71          public static T Create<T>(params object[] args)
     72              where T : class
     73          {
     74              var generator = new ProxyGenerator();
     75  
     76              var options = new ProxyGenerationOptions();
     77  
     78              foreach (MixinAttribute attribute in typeof(User).GetCustomAttributes(true))
     79              {
     80                  var mixin = Activator.CreateInstance(attribute.MixinType);
     81  
     82                  options.AddMixinInstance(mixin);
     83              }
     84  
     85              var target = Activator.CreateInstance(typeof(T), args) as T;
     86  
     87              var proxy = generator.CreateClassProxyWithTarget(target, options);
     88  
     89              foreach (var mixin in options.MixinsAsArray())
     90              {
     91                  foreach (var property in mixin.GetType().GetProperties())
     92                  {
     93                      if (property.GetCustomAttributes(typeof(MixinTargetAttribute), true).Any())
     94                      {
     95                          property.SetValue(mixin, target);
     96                      }
     97                  }
     98              }
     99  
    100              return proxy;
    101          }
    102      }
    103  
    104      [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
    105      public class MixinAttribute : Attribute
    106      {
    107          public MixinAttribute(Type mixinType)
    108          {
    109              this.MixinType = mixinType;
    110          }
    111  
    112          public Type MixinType { get; set; }
    113      }
    114  
    115      public class MixinTargetAttribute : Attribute
    116      {
    117      }
    118  }

    示例(C++)

    class Enjoyable
     {
     public:
         Enjoyable(void);
         ~Enjoyable(void);
         void Play();
         virtual string GetName() = 0;
     };
     
     class Workable
     {
     public:
         Workable(void);
         ~Workable(void);
         void Work();
         virtual string GetName() = 0;
     };
     
     class User: public Enjoyable, public Workable
     {
     public:
         User(void);
         ~User(void);
     
     private:
         string name;
     
     public: 
         string GetName();
         void SetName(string name);
     };
     
     User::User(void)
     {
     }
     
     User::~User(void)
     {
     }
     
     string User::GetName()
     {
         return this->name;
     }
     
     void User::SetName(string name)
     {
         this->name = name;
     }
     
     void Enjoyable::Play(){
         cout << ( this->GetName() + "play");
     }
     
     void Workable::Work(){
         cout << ( this->GetName() + "work");
     }
    

    示例(Ruby)

     1 module Enjoyable
     2      def play
     3          puts(self.name + "-play")
     4      end
     5  end
     6  
     7  module Workable
     8      def work
     9          puts(self.name + "-work")
    10      end
    11  end
    12  
    13  class User
    14      include Enjoyable, Workable
    15  
    16      attr_accessor :name
    17  end
    18  
    19  user = User.new
    20  user.name = "段光伟"
    21  user.play
    22  user.work

     代码示例(Java的Qi4j)

    示例地址:http://qi4j.org/latest/two-minutes-intro.html

     代码示例(Python)

    user.py

    class User():
            def __init__(self):
                    self.name = "unkwnow"
    
            from Enjoyable import play
            from Workable import work
    
            def getName(self):
                    return self.name
    
            def setName(self, name):
                    self.name = name
    
    user = User()
    user.setName("段光伟")
    user.play()
    user.work()
            
    

    Enjoyable.py

    def play(self):
    	print(self.name + "-play")
    

    Workable.py

    def work(self):
    	print(self.name + "-work")
    

    备注

    在学习一门语言的时候,如何模拟Mixin是我必须思考的一个东西。

  • 相关阅读:
    Pandas的基础用法
    独热编码处理文本属性
    DataFrame数据输出时因行、列太多显示不全
    pandas中iloc与loc的区别
    “第五空间”智能安全大赛Misc-wp
    Mac 终端$ 与%切换
    01.数据分析介绍
    02.指标数据库设计
    【杭州城市数据大脑规划2018-2022】学习记录
    【京东基于spark的风控系统架构实践和技术细节】学习记录
  • 原文地址:https://www.cnblogs.com/happyframework/p/3040461.html
Copyright © 2011-2022 走看看