您的位置:首页 > 其它

设计原则:请重新审视“多重继承”,找机会拥抱一下“掺入(Mixin)”

2013-04-25 07:53 363 查看

名称解释

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

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

使用动机

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

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

示例(ExtJs4.2)

/// <reference path="../ext-all-debug-w-comments.js" />
Ext.define('Enjoyable', {
play: function () {
console.log(this.getName() + '-play');
}
});

Ext.define('Workable', {
work: function () {
console.log(this.getName() + '-work');
}
});

Ext.define('User', {
mixins: {
'enjoyable': 'Enjoyable',
'workable': 'Workable'
},
config: { name: 'unknow' },

constructor: function () {
var me = this;

me.initConfig(arguments);
},

eat: function () {
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
});

var user = Ext.create('User');

user.setName('段光伟');

user.play();
user.work();


示例(C#扩展方法)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MixinDemo
{
public class User
{
public string Name { get; set; }
}

public static class Enjoyable
{
public static void Play(this User user)
{
Console.WriteLine(user.Name + "-play");
}
}

public static class Workable
{
public static void Work(this User user)
{
Console.WriteLine(user.Name + "-work");
}
}
}


示例(C#动态代理)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Castle.DynamicProxy;
using Castle.DynamicProxy.Generators;

namespace MixinStudy
{
class Program
{
static void Main(string[] args)
{
var proxy = Factory.Create<User>();
proxy.Id = Guid.NewGuid();
proxy.Name = "段光伟";

(proxy as ITeacher).Teach();
(proxy as IFather).Play();
}
}

[Mixin(typeof(Teacher))]
[Mixin(typeof(Father))]
public class User
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
}

public interface ITeacher
{
User User { get; set; }

void Teach();
}

public class Teacher : ITeacher
{
[MixinTarget]
public User User { get; set; }

public void Teach()
{
Console.WriteLine("我教你读书吧:" + this.User.Name);
}
}

public interface IFather
{
User User { get; set; }

void Play();
}

public class Father : IFather
{
[MixinTarget]
public User User { get; set; }

public void Play()
{
Console.WriteLine("我陪你玩吧:" + this.User.Name);
}
}

public static class Factory
{
public static T Create<T>(params object[] args)
where T : class
{
var generator = new ProxyGenerator();

var options = new ProxyGenerationOptions();

foreach (MixinAttribute attribute in typeof(User).GetCustomAttributes(true))
{
var mixin = Activator.CreateInstance(attribute.MixinType);

options.AddMixinInstance(mixin);
}

var target = Activator.CreateInstance(typeof(T), args) as T;

var proxy = generator.CreateClassProxyWithTarget(target, options);

foreach (var mixin in options.MixinsAsArray())
{
foreach (var property in mixin.GetType().GetProperties())
{
if (property.GetCustomAttributes(typeof(MixinTargetAttribute), true).Any())
{
property.SetValue(mixin, target);
}
}
}

return proxy;
}
}

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class MixinAttribute : Attribute
{
public MixinAttribute(Type mixinType)
{
this.MixinType = mixinType;
}

public Type MixinType { get; set; }
}

public class MixinTargetAttribute : Attribute
{
}
}


示例(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)

module Enjoyable
def play
puts(self.name + "-play")
end
end

module Workable
def work
puts(self.name + "-work")
end
end

class User
include Enjoyable, Workable

attr_accessor :name
end

user = User.new
user.name = "段光伟"
user.play
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是我必须思考的一个东西。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: