我想在我的“小”项目中使用OCP规则。实际上我有一个实现这个问题。让我告诉你我写了什么。
abstract class AnimationType {
public abstract createAnimation(timing: number): { in: string, out: string };
}
class FadingAnimation extends AnimationType {
public createAnimation(timing: number): { in: string, out: string } {
return { in: 'opacity: 0', out: 'opacity: 1' }
}
}
class TransformAnimation extends AnimationType {
public createAnimation(timing: number): { in: string, out: string } {
return { in: 'transform: translateX(-100%)', out: 'transform: translateX(100%)' }
}
}
class AnimationCreator {
private timing: number;
constructor(time: number) {
this.timing = time;
}
getAnimation(animation: AnimationType): { in: string, out: string } {
return animation.createAnimation(this.timing);
}
}
我写得好吗?如果我这样做,那么实际上我获得了什么?如果我想添加这个动画,我需要发送FadingAnimation类的对象。如果我想要变换动画我需要发送TransformAnimation类的对象 - 所以某处我必须使用switch(this.animationType)。
答案 0 :(得分:2)
我同意Aluan Haddad的观点。不要在这里用简单的JAVA-Patterns思考。虽然Typescript看起来很像C#,因此甚至有点像JAVA,但它最终仍然是JavaScript。正如您从JAVA所了解的那样,继承规则在这里不起作用。不要试图建立复杂的继承模式或相关的设计原则。使用Typescript,您必须调整编码方式。
解决问题的一个好方法是使用带有2个返回所需对象的方法的普通服务。
e.g。
import { Injectable } from '@angular/core';
@Injectable()
export class AnimationTypeService {
constructor() {}
getFadingAnimation(timing: number): { in: string, out: string } {
return { in: 'opacity: 0', out: 'opacity: 1' };
}
getTransformAnimation(timing: number): { in: string, out: string } {
return { in: 'transform: translateX(-100%)', out: 'transform: translateX(100%)' };
}
}
答案 1 :(得分:2)
上面的代码并不一定需要面向对象。 AnimationType
类没有状态,不能从多个实例中受益,因此不需要。除非使用animation instanceof TransformAnimation
来区分类实例(并且这不是应该用开放原理来完成的),否则不会使用这些类。
AnimationType
类可以用功能方法替换:
interface IAnimation {
type?: string;
in: string;
out: string;
}
type TAnimationFactory = (timing: number) => IAnimation;
const createFadeAnimation: TAnimationFactory = (timing: number) => {
return { in: 'opacity: 0', out: 'opacity: 1' };
}
class AnimationCreator {
private timing: number;
constructor(time: number) {
this.timing = time;
}
getAnimation(animationFactory: TAnimationFactory): IAnimation {
return animationFactory(this.timing);
}
}
取决于AnimationCreator
的作用,它也可以替换为函数,或者取消直接使用动画工厂函数。
如果AnimationType
有状态,则可能会发生变化,例如它接受transform%作为构造函数参数。但在这种情况下,不清楚为什么transform
属性应该考虑与timing
不同的类型 - 两者都可以从一个动画到另一个动画不同,因此在构造时定义。在这种情况下,AnimationCreator
不需要timing
,因此它是无国籍的,其目的不明确。
答案 2 :(得分:1)
原则和模式绝对可在语言之间转换。当你跨越范式的范围时,它们可能不太适用。 SOLID原则和OOP模式适用于任何面向对象,而不仅仅是Java。
请记住,TypeScript / JavaScript不仅仅是面向对象的。
问题不在于您是否试图从其他语言的原则中汲取经验。这里的问题是你试图从这个原则开始。
良好的代码设计,无论您使用何种范例,都要从您想要解决的问题开始。在寻找模式或应用原则之前编写更多代码,因此设计可以从应用程序增长时发现的实际问题中找到。
从一个原则开始,你太早决定问题最终会是什么;并且您的设计可能会让您远离清洁代码的目标。
模式和原则是高度可转移的,但要等待你遇到问题的信号,而不是过早地应用某种解决方案。
在您的情况下,您可以用最简单的方式解决问题。如果您有测试指导您,您可以稍后轻松更新实施细节。
也许在你的情况下,一个简单的字典/对象就足够了。
const animationType = {
fading: {
in: 'opacity: 0',
out: 'opacity: 1'
},
transforming: {
in: 'transform: translateX(-100%)',
out: 'transform: translateX(100%)'
}
};
如果您不想强制执行fading
和transforming
,则可以输入此选项以允许任何密钥 - 但您还不需要添加此灵活性:
interface AnimationTypes {
[key: string]: { in: string, out: string };
}