这种设计是否需要接口?

时间:2014-11-01 03:25:13

标签: c# oop inheritance interface abstract-class

我正在为邻居做一个小应用程序,目前对设计很困惑。一开始看起来很简单,但现在我被卡住了。我理解继承因此,

  • 所有礼物必须包装好。
  • 礼物是一个抽象的类。
  • Wrapping Style是一个抽象类。
  • 生日礼物继承自礼物。
  • Origami Style继承自Wrapping Style。

场景:用户通过其身份向商店赠送礼物(例如bday for family,bday for colleague )。所以有一个同事的生日礼物,不同于一个家庭的礼物。用户指定他们喜欢使用哪种包装样式。 (例如Origami,Western )在这种情况下,假设同事的生日礼物必须使用Origami下的生日风格包装。

但是如何将礼物与包装连接起来呢?起初包装看起来像是我的界面。所以礼物实现它。但是,包装每个主要包装样式具有子包装样式的事实使其变得复杂。同事的礼物对象生日怎么知道要实现哪个界面?它似乎是生日,婚礼也应该是抽象类,因为只有第3代礼品类才是具体的类。

如何让这个设计变得有意义而且现在很容易编码,以后可以进行修改/改进?

enter image description here

3 个答案:

答案 0 :(得分:1)

为了将每件礼物与包装相关联,您想要实现包装。那样不行。相反,将包装作为变量包含在Gift中。

你似乎有方法是使用抽象类(基本上是部分实现):

public abstract class Gift
{
    public IWrappingStyle wrapping { get; private set; }

    public Gift(IWrappingStyle wrapping)
    {
        this.wrapping = wrapping;
    }

    public void Unwrap()
    {
        // code common to all gifts for unwrapping
        // ...
    }
}

public interface IWrappingStyle
{

}

然后,您可以继续将第二级类型表示为包装样式的接口和礼品的抽象类,将类作为其他所需类型的最低级别。添加一个新的就像添加一个新类一样简单。

然后使用,你可以这样做:

Gift g = new GraduationSchoolGift(new OrigamiBirthdayWrapping());

别忘了使用文件夹!

Folders to stay organized.


但是,除非你对不同的包装有一些特定的不同行为,我认为你可以使用更简单的布局:

public class Gift
{
    public String GiftType { get; private set; }
    public String WrappingStyle { get; private set; }

    public Gift(String giftType, String wrappingStyle)
    {
        this.GiftType = giftType;
        this.WrappingStyle = wrappingStyle;
    }
}

然后,如果您(再次)将文件整理到如下文件夹中:

Organized

以下是各自的文件(命名空间很重要):

礼品类型:

namespace GiftWrapping.GiftTypes
{
    public class Birthday
    {
        public static const String FIFTH_BIRTHDAY = "Birthday Fifth";
        public static const String TENTH_BIRTHDAY = "Birthday Tenth";
    }
}

namespace GiftWrapping.GiftTypes
{
    public class Wedding
    {
        public static const String FAMILY = "Wedding Family";
        public static const String FRIENDS = "Wedding Friends";
    }
}

包装样式:

namespace GiftWrapping.WrappingStyles
{
    public class Origami
    {
        public static const String BIRTHDAY = "Origami Birthday";
        public static const String WEDDING = "Origami Wedding";
    }
}

namespace GiftWrapping.WrappingStyles
{
    public class Western
    {
        public static const String SCHOOL = "Western School";
        public static const String WEDDING = "Western Wedding";
        public static const String UNIVERSITY = "Western University";
    }
}

现在用法变为:

Gift g = new Gift(GiftTypes.Wedding.FAMILY,
                  WrappingStyles.Origami.BIRTHDAY);

答案 1 :(得分:0)

实际上写一个界面是一个很好的做法。在编写单元测试时,它们可以真正帮助您,并且是SOLID的基础。所以你可以试试像:

  public interface IGift
    {
        public void Wrap(IWrappingStyle wrappingStyle)
        {

        }
    }

    public interface IWrappingStyle
    {

    }

有了这种对象依赖性,您可以使用策略模式之类的东西来根据类的类型来处理包装样式。

答案 2 :(得分:-1)

礼品和包装是单独的实体,使用依赖注入。

Class wrapping{
    protected $gift;

    public __construct( $gift ){
        $this->gift = $gift
    }

    public getGift(){
       return $this->gift;
    }

}

Class gift{


}


$g = new gift()

$w = new wrapper($g);

这样您就不需要为每个新礼物更换包装,也不需要为每个新包装更换礼物。无论您是接口礼品,还是将其抽象取决于功能。包装也是如此。不要在“代码”级别混合它们,即使上图显示它们是单独的对象。

就我个人而言,我要么接受礼物,要么为它做一个基础抽象类。然后你可以依赖未来的礼物,包含你需要的代码。

我刚刚意识到这是C,我是怎么做到的。无论如何,即使它不是PHP,这个想法也是一样的。

干杯。