C# 针对此问题的适当设计/设计模式?
我以前发过帖子,但我想它太冗长和不相关了。我的问题也是这样。第二个链接中的一张海报说,答案(为什么你不能做下面的代码)是设计问题,特别是“继承的错误使用”。因此,我想再次与StackOverflow的专家一起检查这个问题,看看这是否真的是一个“坏继承”的问题——但更重要的是,如何修复设计 像海报一样,我也对工厂方法以及如何应用它感到困惑。工厂方法似乎适用于多个具体类,这些类与抽象基类具有完全相同的实现,不添加自己的属性。但是,正如您将在下面看到的,我的具体类构建在抽象基类的基础上,添加额外的属性 我们构建的基础类:C# 针对此问题的适当设计/设计模式?,c#,.net,design-patterns,inheritance,C#,.net,Design Patterns,Inheritance,我以前发过帖子,但我想它太冗长和不相关了。我的问题也是这样。第二个链接中的一张海报说,答案(为什么你不能做下面的代码)是设计问题,特别是“继承的错误使用”。因此,我想再次与StackOverflow的专家一起检查这个问题,看看这是否真的是一个“坏继承”的问题——但更重要的是,如何修复设计 像海报一样,我也对工厂方法以及如何应用它感到困惑。工厂方法似乎适用于多个具体类,这些类与抽象基类具有完全相同的实现,不添加自己的属性。但是,正如您将在下面看到的,我的具体类构建在抽象基类的基础上,添加额外的属性
public abstract class FlatScreenTV
{
public string Size { get; set; }
public string ScreenType { get; set; }
}
public class PhillipsFlatScreenTV : FlatScreenTV
{
// Specific to Phillips TVs. Controls the backlight intensity of the LCD screen.
public double BackLightIntensity { get; set; }
}
public class SamsungFlatScreenTV : FlatScreenTV
{
// Specific to Samsung TVs. Controls the time until the TV automatically turns off.
public int AutoShutdownTime { get; set; }
}
扩展类示例:
public abstract class FlatScreenTV
{
public string Size { get; set; }
public string ScreenType { get; set; }
}
public class PhillipsFlatScreenTV : FlatScreenTV
{
// Specific to Phillips TVs. Controls the backlight intensity of the LCD screen.
public double BackLightIntensity { get; set; }
}
public class SamsungFlatScreenTV : FlatScreenTV
{
// Specific to Samsung TVs. Controls the time until the TV automatically turns off.
public int AutoShutdownTime { get; set; }
}
比如说,更多品牌的平板电视有更多的扩展类。然后,假设我们将它们全部粘贴到一个通用列表中:
public static void Main()
{
List<FlatScreenTV> tvList = new List<FlatScreenTV>();
tvList.Add(new PhillipsFlatScreenTV());
tvList.Add(new SamsungFlatScreenTV());
tvList.Add(new SharpFlatScreenTV());
tvList.Add(new VizioFlatScreenTV());
FlatScreenTV tv = tvList[9]; // Randomly get one TV out of our huge list
}
publicstaticvoidmain()
{
List tvList=新列表();
添加(新屏幕电视());
添加(新SamsungFlatScreenTV());
添加(新的SharpFlatScreenTV());
添加(新的VizioFlatScreenTV());
FlatScreenTV=tvList[9];//从我们庞大的列表中随机抽取一台电视
}
问题:
public abstract class FlatScreenTV
{
public string Size { get; set; }
public string ScreenType { get; set; }
}
public class PhillipsFlatScreenTV : FlatScreenTV
{
// Specific to Phillips TVs. Controls the backlight intensity of the LCD screen.
public double BackLightIntensity { get; set; }
}
public class SamsungFlatScreenTV : FlatScreenTV
{
// Specific to Samsung TVs. Controls the time until the TV automatically turns off.
public int AutoShutdownTime { get; set; }
}
我想访问此变量所属的任何“原始”品牌电视的特定属性。我知道这个品牌,因为如果我调用tv.GetType()
,它会返回正确的“原始”类型,而不是FlatScreenTV
。但是我需要能够将tv
从FlatScreenTV
转换回其原始类型,以便能够访问每个品牌的平板电视的特定属性
问题#1:如果没有临时的黑客和巨大的if-else链来粗暴地猜测“原始”类型,我如何能够正确地动态地投射它?
浏览类似的设计问题后,大多数答案是:你不能。有人说要看工厂模式,也有人说要用接口修改设计,但我不知道如何使用两者来解决这个问题
问题2:那么,我应该如何设计这些类,以便在上面的上下文中访问原始类型的特定属性?
问题#3:这真的是糟糕的继承吗?将是最好的方式我可以提供一个部分答案: 首先阅读利斯科夫的替代原理 其次,您正在创建从FlatScreenTV继承的对象,但显然没有任何目的,因为您希望通过它们的子类型(SpecificTVType)而不是超类型(FlatScreenTV)引用它们-这是继承的一个坏用法,因为它没有使用继承lol 如果您的代码希望访问特定于给定类型的属性,那么您确实希望将此代码封装在该类型中。否则,每次添加新电视类型时,处理电视列表的所有代码都需要更新以反映这一点 因此,您应该在FlatScreenTV上包含一个执行x的方法,并根据需要在TV中重写该方法 因此,基本上在上面的Main方法中,不要认为我想处理TVTypeX,而是应该始终引用basetype,让继承和方法重写处理实际处理的子类型的特定行为 代码
public abstract class FlatScreenTV
{
public virtual void SetOptimumDisplay()
{
//do nothing - base class has no implementation here
}
}
public class PhilipsWD20TV
{
public int BackLightIntensity {get;set;}
public override void SetOptimumDisplay()
{
//Do Something that uses BackLightIntensity
}
}
您的设计违反了“”。换句话说,处理FlatScreenTV列表中项目的代码不应该知道或关心派生类型是什么
假设您的代码需要创建自定义远程控制GUI。只需知道每个电视的名称和属性类型就可以自动生成UI。在这种情况下,您可以执行以下操作以从基类公开自定义属性:
public abstract class FlatScreenTV
{
public FlatScreenTV()
{
CustomProperties = new Dictionary<string,object>();
}
public Dictionary<string,object> CustomProperties { get; private set; }
public string Size { get; set; }
public string ScreenType { get; set; }
}
public class PhillipsFlatScreenTV : FlatScreenTV
{
public PhillipsFlatScreenTV()
{
BackLightIntensity = 0;
}
// Specific to Phillips TVs. Controls the backlight intensity of the LCD screen.
public double BackLightIntensity
{
get { return (double)CustomProperties["BackLightIntensity"]; }
set { CustomProperties["BackLightIntensity"] = value; }
}
}
public class SamsungFlatScreenTV : FlatScreenTV
{
public SamsungFlatScreenTV()
{
AutoShutdownTime = 0;
}
// Specific to Samsung TVs. Controls the time until the TV automatically turns off.
public int AutoShutdownTime
{
get { return (int)CustomProperties["AutoShutdownTime"]; }
set { CustomProperties["AutoShutdownTime"] = value; }
}
}
这将扫描您的插件,并找到一个知道如何为您传入的特定类型的FlatScreenTV构建UI的插件。这意味着,对于您添加的每个新FlatScreenTV,您还需要创建一个知道如何制作其远程控制GUI的插件 “工厂方法适用于多个具体类,这些类与抽象基类[interface]具有完全相同的实现,并且不添加自己的属性。”
不,说得更实际一些,而不是理论上的,工厂方法可以为您提供具体类的对象,其中具体类必须有一些通用方法和接口,但也有一些附加的特定属性
有时我使用的方法每次调用时都会创建相同的类对象,我需要多次调用它,有时我使用的方法会创建几个不同的类对象,这可能会让人困惑,可能是另一个问题
此外,在使用工厂模式时,您对切换语句的进一步评论(带有许多选项),通常为具体类/具体对象提供标识符。这可以是字符串、整数、特殊类型id或枚举类型
您可以改为使用整数/枚举ID,并使用集合查找具体类。您仍然可以利用工厂。工厂的目的是把制造各种电视机的所有重担放在一个地方。如果直截了当地说“一个工厂是为多个具体类设计的,这些具体类具有与抽象基类完全相同的实现”,那么就忘记了多态性 没有法律规定不能使用工厂模式,因为子类声明唯一的属性和方法。但是,使用多态性越多,工厂模式就越有意义。同样作为一个总的指导原则,IMHO认为,构建过程中必须考虑的复杂性越大