【问题标题】:Groovy way to selectively mixin methods from multiple classes从多个类中选择性地混合方法的 Groovy 方法
【发布时间】:2013-05-05 13:00:03
【问题描述】:

我正在编写一个基于 commons-io 的 Groovy 脚本,它监视某个源目录并将其文件与某个目标目录同步。

@Grab(group='commons-io', module='commons-io', version='2.4')
import org.apache.commons.io.monitor.*
import org.apache.commons.io.FileUtils
class BaseSynchronizedFileListener extends FileAlterationListenerAdaptor {
    def srcDir
    def destDir   
    /* Given a source file, returns the destination file */
    File destination(File file) {
        new File(destDir, file.getAbsolutePath() - srcDir.getAbsolutePath())
    }
}
class CopyOnWriteListener extends BaseSynchronizedFileListener {
    @Override 
    void onFileChange(File file) {
        FileUtils.copyFile(file, destination(file))
    }
    @Override
    void onFileCreate(File file) { 
        FileUtils.copyFile(file, destination(file))
    } 
}
class DeleteOnDeleteListener extends BaseSynchronizedFileListener {
    @Override
    void onFileDelete(File file) {
        FileUtils.deleteQuietly(destination(file))
    }
}

除了直接的文件拷贝,我想支持Less->CSS编译,其中源目录的.less文件和目标目录的.css文件同步。

@Grab(group='org.lesscss', module='lesscss', version='1.3.3')
import org.lesscss.LessCompiler
class CompileLessOnWriteListener extends BaseSynchronizedFileListener {
    def compiler = new LessCompiler()
    @Override
    File destination(File file) {
        File dest = super.destination(file)
        new File(dest.parentFile, dest.name - '.less' + '.css')
    }
    void compile(File less) {
        compiler.compile(less, destination(less))
    }
    @Override
    void onFileChange(File less) {
        compile(less)
    }
    @Override
    void onFileCreate(File less) { 
        compile(less)
    } 
}

我遇到的问题是当我尝试创建类DeleteCssOnDeleteLessListener 来处理.less 文件被删除时的情况(这反过来又删除了相应的.css 文件)——我需要的代码要做到这一点存在于两个不同的继承树中。

  • CompileLessOnWriteListener 包含 destination() 方法
  • DeleteOnDeleteListener包含onFileDelete()方法删除destination()方法返回的CSS文件

是否有一种“Groovy 方式”可以选择性地将这两个类的方法混合或继承到一个新类中?

还是只需要硬着头皮为CompileLessOnWriteListenerDeleteCssOnDeleteLessListener 创建一个公共超类?

【问题讨论】:

    标签: groovy multiple-inheritance mixins


    【解决方案1】:

    在我看来,它不是很“Groovy”,看起来也不是很高效,但至少这种方法解决了我的问题,而无需创建一个通用的超类:

    class DeleteCssOnDeleteLessListener extends DeleteOnDeleteListener {
        @Override
        File destination(File f) {
            new CompileLessOnWriteListener(destDir: this.destDir, srcDir: this.srcDir).destination(f)
        }
    }
    

    【讨论】:

      【解决方案2】:

      更新

      更改了实现。让我们看看我是否有这个想法。你需要:

      • 继承两个方法
      • “继承”构造函数
      • 必须是接口的实例

      我认为繁重的元编程在这里会有所帮助。我们可以将两个对象声明给DeleteCssOnDeleteLessListener 委托方法,这些对象将从它访问属性。

      对于界面,我认为您最好使用as Interface 运算符。

      动态“继承”构造函数可能会变得棘手。因为它只有两个属性,所以我已经声明了它们。如果您更喜欢干燥代码,您可以将 getProperty/setProperty 委托给其他两个对象之一:

      class DeleteCssOnDeleteLessListener {
        def destDir, srcDir
        def onLessDelete(file) {
          onFileDelete destination( file )
        }
      }
      
      class CompileLessOnWriteListener {
        def destination(file) {
          "destination $file from $srcDir"
        }
      }
      
      class DeleteOnDeleteListener {
        def onFileDelete(file) {
          "onFileDelete $file and $destDir"
        }
      }
      
      def delete = new DeleteCssOnDeleteLessListener(destDir: "dest/dir", srcDir: "src/dir")
      def compileLess = new CompileLessOnWriteListener()
      def deleteOnDelete = new DeleteOnDeleteListener()
      
      delete.metaClass {
        destination = compileLess.&destination
        onFileDelete = deleteOnDelete.&onFileDelete
      }
      
      compileLess.metaClass.getProperty = { property -> delete.getProperty property }
      deleteOnDelete.metaClass.getProperty = { property -> delete.getProperty property }
      
      assert delete.onLessDelete("style.less") == "onFileDelete destination style.less from src/dir and dest/dir"
      

      【讨论】:

      • 不完全。首先,我无法在初始化时设置 srcDir 和 destDir 属性,例如 (new DeleteCssOnDeleteLessWriter(srcDir: s, destDir: d)。其次,我需要让 DeleteCssOnDeleteLessWriter 成为 FileAlterationListener 的一个实例。遗憾的是,我无法通过实现接口来做到这一点,尽管我可以动态地做到这一点:observer.addListener(delCssListener as FileAlterationListener)。最后,mixin 包括onFileCreateonFileChange 方法。我只需要onFileDelete,因此是问题的“选择性”部分。
      • @Delegate 呢?它自动继承接口。
      • 我可以选择性地@Delegate吗?
      • 我错过了您已编辑答案的通知。让我试试看,我会回复你的。看起来很有希望。
      • 哇,我不记得这个了:-)
      猜你喜欢
      • 2013-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-30
      • 1970-01-01
      • 1970-01-01
      • 2019-11-23
      • 2020-12-08
      相关资源
      最近更新 更多