热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何只为所有形状使用一个移动功能

如何解决《如何只为所有形状使用一个移动功能》经验,为你挑选了1个好方法。

我的代码中的移动功能有问题.我需要它:

    一个可以移动所有形状的功能,或

    具有相同名称的多个函数.

到目前为止,我已经为点,圆和多边形移动了具有不同名称的函数.我无法弄清楚如何为图片制作移动功能.

如果你们能帮助我与移动的图片功能和编辑所有的举动,使他们的工作就像我在开头所描述的功能.

    ;
    ; POINT
    ;

    (defun make-point ()
      (list (list 0 0) :black))

    (defun x (point)
     (caar point))

    (defun y (point)
      (cadar point))

    (defun set-x (point new-x)
      (setf (caar point) new-x)
      point)

    (defun set-y (point new-y)
      (setf (cadar point) new-y)
      point)

    (defun move (point dx dy)
     (set-x point (+ (x point) dx))
     (set-y point (+ (y point) dy))
     point)

    ;
    ; CIRCLE
    ;

    (defun make-circle ()
      (list  (make-point) 1 :black))

    (defun center (circle)
      (car circle))

    (defun radius (circle)
      (cadr circle))

    (defun set-radius (circle new-rad)
      (if (> 0 new-rad)
          (format t "Polomer ma byt kladne cislo, zadali ste : ~s" new-rad)
        (setf (cadr circle) new-rad))
      circle)

    (defun movec (circle dx dy)
      (move (center circle) dx dy)
     circle)

    ;
    ; POLYGON
    ;

    (defun make-polygon ()
      (list nil :black))

    (defun items (shape)
     (car shape))

    (defun set-items (shape val)
      (setf (car shape) val)
      shape)

    (defun movep (polygon dx dy)
      (mapcar (lambda (b) (move b dx dy))  (items polygon))
      polygon)

    ;
    ; PICTURE
    ;

    (defun make-picture ()
      (list nil :black))

    ;(defun movepi (picture dx dy)) 

    ; items, set-items used for polygon and picture

coredump.. 6

您的对象只是列表,您将很难区分不同类型的形状.您可以在列表前面添加一个关键字,一个标签类型(例如:point,:circle等等),以便根据该标签更好地调度您的移动操作,但那将重新发明轮子,即对象.

简单的功能和列表

一个可以移动所有形状的功能

您可以这样做,前提是您可以调度您正在使用的实际对象类型.move应该能够知道正在移动的是什么样的形状.如果可以将对象类型添加为列表的CAR,则更改数据结构,并使用CASE分派,然后根据需要移动每个对象.

或多个具有相同名称的功能.

这是不可能的,至少在同一个包中.

CLOS

(defpackage :pic (:use :cl))
(in-package :pic)

多个形状有颜色,所以让我们定义一个表示具有颜色成分的对象的类:

(defclass has-color ()
  ((color :initarg :color :accessor color)))

如果您不熟悉CLOS(Common Lisp对象系统),则上面定义了一个名为的类has-color,没有超类和单个插槽color.访问者的名字与读写器通用的功能,例如,你可以做(color object)检索对象,并(setf (color object) color)给对象的颜色设置为彩色.所述:initarg用于定义的关键字参数是在被使用make-instance.

在下面,我们定义一个point,它有一个颜色和附加xy坐标.

(defclass point (has-color)
  ((x :initarg :x :accessor x)
   (y :initarg :y :accessor y)))

圆圈相同:

(defclass circle (has-color)
  ((center :initarg :center :accessor center)
   (radius :initarg :radius :accessor radius)))

还有一个多边形:

(defclass polygon (has-color)
  ((points :initarg :points :accessor points)))

最后,图片是一系列形状:

(defclass picture ()
  ((shapes :initarg :shapes :accessor shapes)))

您可以按如下方式创建一个圆圈:

(make-instance 'circle
               :center (make-instance 'point :x 10 :y 30)
               :color :black))

如果需要,您还可以定义更短的构造函数.

现在,您可以对move对象使用泛型函数.首先定义它DEFGENERIC,声明泛型函数的签名,以及其他选项.

(defgeneric move (object dx dy)
  (:documentation "Move OBJECT by DX and DY"))

现在,您可以向该泛型函数添加方法,并且您的泛型函数将基于一个或多个特化器和/或限定符分派给它们.

例如,您按如下方式移动一个点:

(defmethod move ((point point) dx dy)
  (incf (x point) dx)
  (incf (y point) dy))

你可以看到我们move根据第一个参数的类来专门化,这里命名为point.当绑定到的值point是类时,应用该方法point.调用INCF隐式调用(setf x)(setf y)上面定义的.

移动圆圈意味着移动其中心:

(defmethod move ((circle circle) dx dy)
  (move (center circle) dx dy))

您可以在任何类上专门化泛型函数,例如标准SEQUENCE类.它使用相同的偏移量移动序列中的所有对象:

(defmethod move ((sequence sequence) dx dy)
  (map () (lambda (object) (move object dx dy)) sequence))

这对多边形很有用:

(defmethod move ((polygon polygon) dx dy)
  (move (points polygon) dx dy))

还有图片:

(defmethod move ((picture picture) dx dy)
  (move (shapes picture) dx dy))

不变的版本

您还可以move构建新实例,但这需要以某种方式复制现有对象.一个简单的方法是使用一个泛型函数,用一个源实例填充目标实例:

(defgeneric fill-copy (source target)
  (:method-combination progn))

这里的方法组合意味着fill-copy运行满足的所有方法,而不是仅运行最具体的方法.该progn建议的所有方法在运行progn块,一前一后.通过上面的定义,我们可以定义一个简单的copy-object泛型函数:

(defgeneric copy-object (source)
  (:method (source)
    (let ((copy (allocate-instance (class-of source))))
      (fill-copy source copy)
      copy)))

上面定义了一个名为的泛型函数copy-object,以及一个T类型对象(任何对象)的默认方法. ALLOCATE-INSTANCE创建一个实例但不初始化它.该方法用于FILL-COPY复制槽值.

例如,您可以定义如何复制color具有颜色的任何对象的插槽:

(defmethod fill-copy progn ((source has-color) (target has-color))
  (setf (color target) (color source)))

请注意,您在此处有多个分派:源对象和目标对象必须是has-color要调用的方法的类.该progn方法组合允许分配的工作fill-copy不同,解耦,方法中:

(defmethod fill-copy progn ((source point) (target point))
  (setf (x target) (x source))
  (setf (y target) (y source)))

如果您指出fill-copy,可以根据以下类层次结构应用两种方法point:为其定义的类has-color,以及专用于point类的类(对于两个参数).该progn方法相结合,确保两者都执行.

由于某些插槽可以解除绑定,因此可能会fill-copy失败.我们可以通过添加错误处理程序来解决这个问题 fill-copy:

(defmethod fill-copy :around (source target)
  (ignore-errors (call-next-method)))

(call-next-method)表单调用其他方法(由progn限定符定义的方法),但我们将其包装在内部ignore-errors.这里没有定义颜色,但复制成功:

(copy-object (make-point :x 30 :y 20))
=> #

我们现在可以保留现有的,变异的move方法,并将它们包装在:around首先制作副本的专用方法中:

(defmethod move :around (object dx dy)
  ;; copy and mutate
  (let ((copy (copy-object object)))
    (prog1 copy
      (call-next-method copy dx dy))))

为了了解会发生什么,请定义一个方法PRINT-OBJECT:

(defmethod print-object ((point point) stream)
  (print-unreadable-object (point stream :identity t :type t)
    (format stream "x:~a y:~a" (x point) (y point))))

现在,移动一点创造了一个新观点:

(let ((point (make-instance 'point :x 10 :y 20)))
  (list point (move point 10 20)))

=> (# #)

您仍然需要更改SEQUENCE类型的方法,该类型当前会丢弃返回值move,但除此之外,对现有代码几乎没有任何更改.

另请注意,上述方法主要用于描述CLOS的各种用途,在实践中,您可能会选择某种方式移动点(可变或不可变),或者您将使用不同的函数而不是单个通用的(例如,mut-move和move).



1> coredump..:

您的对象只是列表,您将很难区分不同类型的形状.您可以在列表前面添加一个关键字,一个标签类型(例如:point,:circle等等),以便根据该标签更好地调度您的移动操作,但那将重新发明轮子,即对象.

简单的功能和列表

一个可以移动所有形状的功能

您可以这样做,前提是您可以调度您正在使用的实际对象类型.move应该能够知道正在移动的是什么样的形状.如果可以将对象类型添加为列表的CAR,则更改数据结构,并使用CASE分派,然后根据需要移动每个对象.

或多个具有相同名称的功能.

这是不可能的,至少在同一个包中.

CLOS

(defpackage :pic (:use :cl))
(in-package :pic)

多个形状有颜色,所以让我们定义一个表示具有颜色成分的对象的类:

(defclass has-color ()
  ((color :initarg :color :accessor color)))

如果您不熟悉CLOS(Common Lisp对象系统),则上面定义了一个名为的类has-color,没有超类和单个插槽color.访问者的名字与读写器通用的功能,例如,你可以做(color object)检索对象,并(setf (color object) color)给对象的颜色设置为彩色.所述:initarg用于定义的关键字参数是在被使用make-instance.

在下面,我们定义一个point,它有一个颜色和附加xy坐标.

(defclass point (has-color)
  ((x :initarg :x :accessor x)
   (y :initarg :y :accessor y)))

圆圈相同:

(defclass circle (has-color)
  ((center :initarg :center :accessor center)
   (radius :initarg :radius :accessor radius)))

还有一个多边形:

(defclass polygon (has-color)
  ((points :initarg :points :accessor points)))

最后,图片是一系列形状:

(defclass picture ()
  ((shapes :initarg :shapes :accessor shapes)))

您可以按如下方式创建一个圆圈:

(make-instance 'circle
               :center (make-instance 'point :x 10 :y 30)
               :color :black))

如果需要,您还可以定义更短的构造函数.

现在,您可以对move对象使用泛型函数.首先定义它DEFGENERIC,声明泛型函数的签名,以及其他选项.

(defgeneric move (object dx dy)
  (:documentation "Move OBJECT by DX and DY"))

现在,您可以向该泛型函数添加方法,并且您的泛型函数将基于一个或多个特化器和/或限定符分派给它们.

例如,您按如下方式移动一个点:

(defmethod move ((point point) dx dy)
  (incf (x point) dx)
  (incf (y point) dy))

你可以看到我们move根据第一个参数的类来专门化,这里命名为point.当绑定到的值point是类时,应用该方法point.调用INCF隐式调用(setf x)(setf y)上面定义的.

移动圆圈意味着移动其中心:

(defmethod move ((circle circle) dx dy)
  (move (center circle) dx dy))

您可以在任何类上专门化泛型函数,例如标准SEQUENCE类.它使用相同的偏移量移动序列中的所有对象:

(defmethod move ((sequence sequence) dx dy)
  (map () (lambda (object) (move object dx dy)) sequence))

这对多边形很有用:

(defmethod move ((polygon polygon) dx dy)
  (move (points polygon) dx dy))

还有图片:

(defmethod move ((picture picture) dx dy)
  (move (shapes picture) dx dy))

不变的版本

您还可以move构建新实例,但这需要以某种方式复制现有对象.一个简单的方法是使用一个泛型函数,用一个源实例填充目标实例:

(defgeneric fill-copy (source target)
  (:method-combination progn))

这里的方法组合意味着fill-copy运行满足的所有方法,而不是仅运行最具体的方法.该progn建议的所有方法在运行progn块,一前一后.通过上面的定义,我们可以定义一个简单的copy-object泛型函数:

(defgeneric copy-object (source)
  (:method (source)
    (let ((copy (allocate-instance (class-of source))))
      (fill-copy source copy)
      copy)))

上面定义了一个名为的泛型函数copy-object,以及一个T类型对象(任何对象)的默认方法. ALLOCATE-INSTANCE创建一个实例但不初始化它.该方法用于FILL-COPY复制槽值.

例如,您可以定义如何复制color具有颜色的任何对象的插槽:

(defmethod fill-copy progn ((source has-color) (target has-color))
  (setf (color target) (color source)))

请注意,您在此处有多个分派:源对象和目标对象必须是has-color要调用的方法的类.该progn方法组合允许分配的工作fill-copy不同,解耦,方法中:

(defmethod fill-copy progn ((source point) (target point))
  (setf (x target) (x source))
  (setf (y target) (y source)))

如果您指出fill-copy,可以根据以下类层次结构应用两种方法point:为其定义的类has-color,以及专用于point类的类(对于两个参数).该progn方法相结合,确保两者都执行.

由于某些插槽可以解除绑定,因此可能会fill-copy失败.我们可以通过添加错误处理程序来解决这个问题 fill-copy:

(defmethod fill-copy :around (source target)
  (ignore-errors (call-next-method)))

(call-next-method)表单调用其他方法(由progn限定符定义的方法),但我们将其包装在内部ignore-errors.这里没有定义颜色,但复制成功:

(copy-object (make-point :x 30 :y 20))
=> #

我们现在可以保留现有的,变异的move方法,并将它们包装在:around首先制作副本的专用方法中:

(defmethod move :around (object dx dy)
  ;; copy and mutate
  (let ((copy (copy-object object)))
    (prog1 copy
      (call-next-method copy dx dy))))

为了了解会发生什么,请定义一个方法PRINT-OBJECT:

(defmethod print-object ((point point) stream)
  (print-unreadable-object (point stream :identity t :type t)
    (format stream "x:~a y:~a" (x point) (y point))))

现在,移动一点创造了一个新观点:

(let ((point (make-instance 'point :x 10 :y 20)))
  (list point (move point 10 20)))

=> (# #)

您仍然需要更改SEQUENCE类型的方法,该类型当前会丢弃返回值move,但除此之外,对现有代码几乎没有任何更改.

另请注意,上述方法主要用于描述CLOS的各种用途,在实践中,您可能会选择某种方式移动点(可变或不可变),或者您将使用不同的函数而不是单个通用的(例如,mut-move和move).


传统上,类似“具有颜色”的类将被称为“颜色混合”。
推荐阅读
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • ***byte(字节)根据长度转成kb(千字节)和mb(兆字节)**parambytes*return*publicstaticStringbytes2kb(longbytes){ ... [详细]
  • 本文介绍了在使用Laravel和sqlsrv连接到SQL Server 2016时,如何在插入查询中使用输出子句,并返回所需的值。同时讨论了使用CreatedOn字段返回最近创建的行的解决方法以及使用Eloquent模型创建后,值正确插入数据库但没有返回uniqueidentifier字段的问题。最后给出了一个示例代码。 ... [详细]
author-avatar
lookzana
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有